Help us understand the problem. What is going on with this article?

Xamarin.iOSでiOS向けカスタムキーボードを作る

More than 1 year has passed since last update.

はじめに

Visual Studio 2017 community(2017/9/22時点)のXamarin.iOSを使ってiOS向けのカスタムキーボードを作る方法およびコツをまとめます。

1.新規ソリューションを立ち上げる

説明1.png
まずiOSの単一ビューアプリを選択します。

説明2.png
続いて、アプリ名を設定します。デバイス設定はここではひとまずiPhoneのみにチェックをします。

説明3.png

説明4.png
そのまま次へを押してソリューションを立ち上げます。

2.キーボードのExtensionプロジェクトを追加する

説明5.png
ソリューションのルートから「新しいプロジェクトを追加」を選択します。

説明6.png
iOSのExtension->Custom Keyboard Extentionを選択します。

説明7.png
拡張機能名がキーボードの名前になります。

説明8.png

説明9.png

そのまま次へを選択すると、Custom Keyboardのプロジェクトが追加されます。

3.キーボードのViewとそれを司るクラスファイルを作成する

説明10.png
元からあったiOSCustomKeyboardを副クリックして「新しいファイルを追加」を選択します。

説明11.png
iOS->Table View Cellを選択して、こちらも名前をKeyboardViewにします。これはキーボードのイベントなどを扱うために用意するクラスです。本当はTabel View CellではなくただのViewが良いのですが、追加方法が見つからなかったため、Table View Cellを改造する形で進めます。

説明12.png
そうすると
KeyboardView.csとKeyboardView.designer.cs、KeyboardView.xibが追加されます。

ここで、KeyboardView.csを選択してください。
KeyboardView.csの最低限の編集を行います。
もともとのソースコードは、

~KeyboardView.cs
using System;

using Foundation;
using UIKit;

namespace iOSCustomKeyboard
{
    public partial class KeyboardView : UITableViewCell
    {
        public static readonly NSString Key = new NSString("KeyboardView");
        public static readonly UINib Nib;

        static KeyboardView()
        {
            Nib = UINib.FromName("KeyboardView", NSBundle.MainBundle);
        }

        protected KeyboardView(IntPtr handle) : base(handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
    }
}

上のようになっていると思います。これを下のように書き換えてください。

~KeyboardView.cs
using System;

using Foundation;
using UIKit;

namespace TestKeyboard
{
    public partial class KeyboardView : UIView
    {
        static KeyboardView()
        {

        }

        protected KeyboardView(IntPtr handle) : base(handle)
        {

        }
    }
}

namespaceと親クラスを変更するのを忘れないでください。

説明13.png
そうしましたら、UITableViewに特化したxibになってしまっていて使えないため、KeyboardView.xibを完全に削除してください。

説明14.png
先ほどと同様にiOSCustomKeyboardを副クリックして「新しいファイルを追加」を選択し、今度はiOS->Viewを選択して、名前をKeyboardViewにして作成します。これでキーボードのレイアウトを編集するxibファイルを生成しなおします。

説明13.png
三つのファイルがiOSCustomKeyboardディレクトリ内に追加されているのを確認してください.

説明15.png
これをTestKeyboardディレクトリにドラッグ&ドロップで移します。

このタイミングでKeyboardView.designer.csを選択してnamespaceをTestKeyboardに変更してください。

KeyboardView.designer.cs
using Foundation;

namespace TestKeyboard
{
    [Register("KeyboardView")]
    partial class KeyboardView
    {
        void ReleaseDesignerOutlets()
        {
        }
    }
}

そうしたらKeyboardView.xibを開いてください。

説明16.png
Viewを選択してプロパティのWidgetのClassをKeyboardViewにしてください。先ほどのnamespaceの変更によってここにClassの候補が表示されるようになります。

これで下準備は完了です。

4.キーボードのViewをレイアウトする

引き続きKeyboardView.xibを編集します。

説明17.png

左上のVIEW ASがGenericとなっているので、iPhone6など自分のデザインしやすいものにしてください。

説明18.png
Viewを選択してプロパティのWidgetのSimulated Metricsを編集してSizeをFreeformに、Status BarをNoneに変更してください。

説明19.png
ツールボックスからButtonを選んでドラッグ&ドロップしてButtonを4つ配置してください。

説明20.png
Buttonの大きさをいい感じにして、表示している文字をA, B, Next, Spaceにしてください。同時にIdentityのNameにAButton、BButton、NextButton、SpaceButtonと名前を設定してください。

説明21.png
Aボタンを選択して、プロパティのEventsを開き、TouchのUp Insideの欄にPushKeyと入力してReturnキーを押してください。この時、イベントハンドラの名前を大文字から始まるようにしないとエラーになります。

説明22.png
自動的にKeyboardView.csが開き、イベントハンドラの追加が行えます。追加位置はアローキーにて変更できます。

説明23.png
Returnキーを押して確定するとこのようにボタンを押した時のイベントハンドラのコードが自動で挿入されます。

今度はBボタンを選択し、Aボタンと同じイベントハンドラに接続します。
説明24.png
すでに一度作ってあるイベントハンドラは候補から選択できます。

同様にしてNextボタンはPushNext、SpaceボタンはPushSpaceというイベントハンドラ名でコードと関連付けを行ってください。

結果KeyboardView.csはこのようになります。

KeyboardView.cs
using System;

using Foundation;
using UIKit;

namespace TestKeyboard
{
    public partial class KeyboardView : UIView
    {
        static KeyboardView()
        {

        }

        protected KeyboardView(IntPtr handle) : base(handle)
        {

        }

        partial void PushKey(UIButton sender)
        {
            throw new NotImplementedException();
        }

        partial void PushNext(UIButton sender)
        {
            throw new NotImplementedException();
        }

        partial void PushSpace(UIButton sender)
        {
            throw new NotImplementedException();
        }
    }
}

ちなみにKeyboardView.designer.csの方は自動で編集が進み、このようになっています。

KeyboardView.designer.cs
using Foundation;
using System;
using System.CodeDom.Compiler;

namespace TestKeyboard
{
    [Register ("KeyboardView")]
    partial class KeyboardView
    {
        [Outlet]
        [GeneratedCode ("iOS Designer", "1.0")]
        UIKit.UIButton AButton { get; set; }

        [Outlet]
        [GeneratedCode ("iOS Designer", "1.0")]
        UIKit.UIButton BButton { get; set; }

        [Outlet]
        [GeneratedCode ("iOS Designer", "1.0")]
        UIKit.UIButton NextButton { get; set; }

        [Outlet]
        [GeneratedCode ("iOS Designer", "1.0")]
        UIKit.UIButton SpaceButton { get; set; }

        [Action ("PushKey:")]
        [GeneratedCode ("iOS Designer", "1.0")]
        partial void PushKey (UIKit.UIButton sender);

        [Action ("PushNext:")]
        [GeneratedCode ("iOS Designer", "1.0")]
        partial void PushNext (UIKit.UIButton sender);

        [Action ("PushSpace:")]
        [GeneratedCode ("iOS Designer", "1.0")]
        partial void PushSpace (UIKit.UIButton sender);

        void ReleaseDesignerOutlets ()
        {
            if (AButton != null) {
                AButton.Dispose ();
                AButton = null;
            }

            if (BButton != null) {
                BButton.Dispose ();
                BButton = null;
            }

            if (NextButton != null) {
                NextButton.Dispose ();
                NextButton = null;
            }

            if (SpaceButton != null) {
                SpaceButton.Dispose ();
                SpaceButton = null;
            }
        }
    }
}

最後にボタンがわかるように背景色を設定しましょう。
Viewやボタンを選択してプロパティのWidgetのViewのBackground項目を設定すると背景色を変更できます。
説明25.png

レイアウト周りの下準備は以上です。

5.コーディング

KeyboardView.csを開きます。まずは下のように追記してください。

KeyboardView.cs
using System;

using Foundation;
using UIKit;

namespace TestKeyboard
{
    public interface KeyboardViewDelegate
    {
        void selectKey(string key);
        void selectNext();
        void selectSpace();
    }

    public partial class KeyboardView : UIView
    {
        public KeyboardViewDelegate delegate_;

        static KeyboardView()
        {}

        protected KeyboardView(IntPtr handle) : base(handle)
        {}

        public override void AwakeFromNib()
        {
            AButton.Layer.CornerRadius = 10;
            BButton.Layer.CornerRadius = 10;
            NextButton.Layer.CornerRadius = 10;
            SpaceButton.Layer.CornerRadius = 10;
        }

        partial void PushKey(UIButton sender)
        {
            delegate_.selectKey(sender.CurrentTitle);
        }

        partial void PushNext(UIButton sender)
        {
            delegate_.selectNext();
        }

        partial void PushSpace(UIButton sender)
        {
            delegate_.selectSpace();
        }
    }
}

続いて、KeyboardViewController.csを編集します。
まずは余計なものを消して綺麗にしましょう。

KeyboardViewController.cs
using System;

using ObjCRuntime;
using Foundation;
using UIKit;

namespace TestKeyboard
{
    public partial class KeyboardViewController : UIInputViewController
    {

        protected KeyboardViewController(IntPtr handle) : base(handle)
        {}

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
        }

        public override void UpdateViewConstraints()
        {
            base.UpdateViewConstraints();
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
        }

        public override void TextWillChange(IUITextInput textInput)
        {}

        public override void TextDidChange(IUITextInput textInput)
        {}
    }
}

綺麗にできたら下のように追記してください。

KeyboardViewController.cs
using System;

using ObjCRuntime;
using Foundation;
using UIKit;

namespace TestKeyboard
{
    public partial class KeyboardViewController : UIInputViewController, KeyboardViewDelegate
    {
        KeyboardView kv;

        protected KeyboardViewController(IntPtr handle) : base(handle)
        {}

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
        }

        public override void UpdateViewConstraints()
        {
            base.UpdateViewConstraints();
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            kv = UINib.FromName("KeyboardView", null).Instantiate(this, null)[0] as KeyboardView;
            kv.delegate_ = this;
            View.AddSubview(kv);
        }

        public override void TextWillChange(IUITextInput textInput)
        {}

        public override void TextDidChange(IUITextInput textInput)
        {}

        public void selectKey(string key)
        {
            TextDocumentProxy.InsertText(key);
        }

        public void selectNext()
        {
            AdvanceToNextInputMode();
        }

        public void selectSpace()
        {
            TextDocumentProxy.InsertText(" ");
        }
    }
}

コーディングは以上です。

6.実行

レイアウトをしたサイズのiPhoneをシミュレータで指定して実行しましょう。真っ白な画面が出てくると思います。
ホームボタンを押すか、shift + command + H でホーム画面を表示して、環境設定を開き、一般->言語->キーボードから自作したiOSCustomKeyboardを追加しましょう。
リマインダアプリなどでキーボードの動作を確認できます。

説明26.png説明27.png説明28.png

7.終わりに

XamarinでのiOSカスタムキーボード開発の基礎の基礎ですが、なんとかやり方を確立できてよかったです。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away