kenichiro246’s blog

主にC#での仕事をしてます。今はXamarinに飛び込みハマり中。基本的に作ることが好き。

UIKeyCommandを使ってバーコードリーダーの入力を受け取る(Xamarin版)

BluetoothiOSバイスに接続されているHIDプロファイルのキーボード入力値を取得し、画面に表示させる方法です。
通常は「Bluetooth LE Plugin for Xamarin」などのプラグインなどを使用し、バーコードなどの入力値を取得することになりますが、ここではiOSのUIKeyCommandを利用し、取得する方法を纏めました。
(とはいうものの、「Bluetooth LE Plugin for Xamarin」は全然触れておらず現在勉強中)

本来ならばSPPで値をとるのだろうけど、iOSに限ってはUIKeyCommandのAPIがあるので、これを使用し、キーボードの値を取得してみます。

参考

以下のサイトを元にしています。
細かい用途や考え方などが纏まっており、大変勉強になります。
* UIKeyCommandを使ってバーコードリーダーの入力を受け取る
* UIKeyCommandでバーコードリーダーの入力を受けとる(Swift版)

実装概要

  1. PCL側にバーコードリーダーで取得した際に呼び出されるメソッドを追記する。
  2. iOSプロジェクトにPageRendererを追加する。
  3. PageRendererにてキーボード入力を取得するためのUIKeyCommandを実装する。
  4. キーボード入力を取得後、1で作成したメソッドを呼び出す。

サンプルコード

GitHubに保存しています。
https://github.com/kenichiro246/KeyCommandSample

サンプルコードの実行イメージ

※準備中。(MacBookのOS再インストールが必要になり、イメージ画が作れず・・・)

実装

以下の通り実装することで取得したバーコードの情報を画面に表示できます。

PCL

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="KeyCommandSample.Page1">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <Label
            x:Name="Label1"
            Text="Welcome to Xamarin Forms!" 
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            />
    </ContentPage.Content>
</ContentPage>
namespace KeyCommandSample
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Page1 : ContentPage
    {
        public Page1()
        {
            InitializeComponent();
        }

        // iOSから呼び出される
        public void SetKeyboardValue(string value)
        {
            Label1.Text = value;
        }
    }
}

iOS

[assembly: ExportRenderer(typeof(KeyCommandSample.Page1), typeof(Page1Renderer))]
namespace KeyCommandSample.iOS
{
    public class Page1Renderer : PageRenderer
    {
        private string _RecvValue = string.Empty;

        public override bool CanBecomeFirstResponder
        {
            get { return true; }
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            string key = string.Empty;
            var selector = new Selector("KeyRecv:");
            for (int i = 0; i <= 127; i++)
            {
                key = ((char)i).ToString();
                UIKeyCommand accelerator1 = UIKeyCommand.Create((NSString)key, 0, selector);
                AddKeyCommand(accelerator1);
                UIKeyCommand acceleratorShift = UIKeyCommand.Create((NSString)key, UIKeyModifierFlags.Shift, selector);
                AddKeyCommand(acceleratorShift);
            }
            UIKeyCommand accelerator2 = UIKeyCommand.Create((NSString)"\n", 0, selector);
            AddKeyCommand(accelerator2);
            UIKeyCommand accelerator3 = UIKeyCommand.Create((NSString)"\r", 0, selector);
            AddKeyCommand(accelerator3);
        }

        [Export("KeyRecv:")]
        public void KeyRecv(UIKeyCommand cmd)
        {
            if (cmd == null)
                return;
            var inputValue = cmd.Input;
            if (inputValue == "\n" || inputValue == "\r")
            {
                SetKeyboardValue(_RecvValue);
                _RecvValue = string.Empty;
            }
            else
            {
                _RecvValue += inputValue;
            }
        }
        public void SetKeyboardValue(string value)
        {
            ((KeyCommandSample.Page1)Element)?.SetKeyboardValue(value);
        }
    }
}

まとめ

今回の作り方では、ページが破棄された時のロジックが未実装であり、そのあたりはもう少し工夫して作りこみたいとは思っています。 また、今回はiOSのみですが、次回はSPPでiOSAndroidも情報を取得できるようにしたいなぁなんて。

Xamarin.Androidで横向きキーボード表示時に画面が隠れないようにする方法

Android端末を横向きにしてキーボードを表示させると、以下のように現在表示されている画面の情報が見えなくなるので、これをXamarin.Androidで解消できるようにします。
Android端末のキーボード設定でも解消できますが、今回はプログラムで制御させてみます。

※キーボードの設定で変更出来ることは@ytabuchiさんから、キーボードの制御が出来ることを@Santea3173さんから教えてもらいました。ありがとうございました。

ゴールは以下の通りCustomEntryにフォーカスが当たった時の挙動になるようにします。
f:id:kenichiro246:20170617174422g:plain:w400

手順

実装する手順は以下のとおりです。実はたったこれだけ。 ポイントとしてはImeActionへの設定値は、ImeFlagsの値をImeActionへキャストしないといけないところ。恥ずかしながら実はここで結構ハマった。

  1. EntryのCustomRendererを作る
  2. EntryのImeActionプロパティを変更する

書いてみよう

では、上記手順のとおり書いてみましょう!
まずはEntryを継承したCustomRenderer用のクラスを準備します。

CustomEntry.cs

namespace KeyboardImeAction
{
    public class CustomEntry : Entry
    {
    }
}  

次にAndroid側のプロジェクトにEntryRendererを継承したクラスを準備します。

CustomEntryDroid.cs

using Android.Views.InputMethods;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(KeyboardImeAction.CustomEntry), typeof(KeyboardImeAction.Droid.CustomEntryDroid))]
namespace KeyboardImeAction.Droid
{
    class CustomEntryDroid : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.ImeOptions = (ImeAction)ImeFlags.NoFullscreen;
            }
        }
    }
}

最後に作成したCustomEntryをContentPageに配置します。
Entryの動きを確認するため、通常のEntryとCustomEntryを配置してみます。

App.cs

public App()
{
    MainPage = new ContentPage
    {
        Content = new StackLayout
        {
            Children = {
                new Label { Text = "Welcome to Xamarin Forms !" },
                new Entry { Placeholder = "Entry" },
                new CustomEntry { Placeholder = "CustomEntry" }
            }
        }
    };
}

これで実行してみましょう。
Entryにフォーカスが当たった状態と、CustomEntryにフォーカスが当たった状態の違いが見れるかと思います。

尚、ImeFlagsはNoFullscreenを指定しており、NoExtractUiでも同じような挙動をしますが、リファレンスを読んでもイマイチよくわかっていないので、後日もう少し検証してみようかと思います。

GitHubにも上げているので良ければ参考にしてください。
https://github.com/kenichiro246/KeyboardImeAction

参考サイト:
http://android.ohwada.jp/archives/4382
https://xamarinhelp.com/accommodate-on-screen-keyboard-xamarin-forms/

ではまた。