iPhoneで文字入力する際のキーボードを、カスタムキーボードに変更した。目的としては、定型文しか入力しないフィールドに対して選択肢を用意し、入力を簡単にすることである。
それだけを目的とするならピッカーでも同じことはできるのだが、現在作っているアプリケーションでは、ピッカーをグルグル回して選択するよりも並んでいるボタン状のものから選ぶ方が好ましいと思われたので、カスタムキーボードにした。
さらに言うと、単に選ぶだけならUIAccessoryViewを使っても同じようなことが出来そうだが、本来のキーボードも併用して切り替えられるようにしたかったので、カスタムキーボードにしてみた次第である。
大雑把な手順は以下の通り。
- UITextFieldクラスを継承して、カスタムテキストフィールドクラスを作る(CustomTextFieldとする)
- Interface BuilderでCustomTextFieldをビューに配置する
- カスタムキーボードに相当する新しいxibファイルを、UIViewベースで作成する(CustomKeyboardInputViewとする)
- xibファイルをInterface Builderで起動し、入力選択肢(キーボードのキー)に相当するボタン(UIButon)を配置する
- 3. で作成したカスタムキーボードに対するビューコントローラクラスを作成する(CustomKeyboardInputViewControllerとする)
- 5. で作成したビューコントローラを、4. で作成したxibでFile’s Ownerに対するビューコントローラに設定する
- 1. で作成したCustomTextField.mを編集し、inputViewメソッドをオーバーライドする。このメソッドで、3.で作成したxibを使ってビューコントローラ(4.で作成したCustomKeyboardInputViewController)を生成し、そのビューコントローラに対するビューを戻す
- CustomKeyboardInputViewController.mを編集し、ビュー上のボタンが押された際のメソッドを記述し、呼び出し元となったカスタムテキストフィールド(CustomTextField)に適切な値をセットする
当然ながら、Interface Builderではなくプログラムでガリガリ書いても同じ(はず)。
この手法の考え方としては、UITextFieldやUITextView(を継承したサブクラス)のinputViewメソッドをオーバーライドして、新たに定義したキーボード(のUIView)を返すようにすれば、カスタムキーボードを表示できる、というものである。
一旦キーボードを表示してしまえば、あとは通常のビュー間でのデータのやりとりと同じ手法で、カスタムキーボードの呼び出し元になったテキストフィールドに、カスタムキーボードで選択したボタンに相当する値をセットしてやればよい。
サンプルソースは以下の通り。
本筋とは関係ない処理は全て削ってある。
本来は、本来のキーボードと切り替えるためのAccessoryViewを作ったり、その切り替え処理を組み込んだり、キーボードで選択したボタンに対する処理など、色々とやることはあるのだが、それらは除外した。
CustomTextField.h
#import@interface CustomTextField : UITextField { } @end
CustomTextField.m
#import "CustomTextField.h" #import "CustomKeyboardInputViewController.h" @implementation CustomTextField - (UIView *)inputView { CustomKeyboardInputViewController *vc = [[CustomKeyboardInputViewController alloc] initWithNibName:@"CustomKeyboardInputView" bundle:nil]; return vc.view; } - (void)dealloc { [super dealloc]; } @end
カスタムキーボード呼び出し元になるxibの設定
カスタムキーボード表示対象のテキストフィールド(上で作成したCustomTextField)をビューに配置する。
カスタムキーボード自体のxib
実行結果
ビュー上のテキストフィールドを選択すると、カスタムキーボードが表示される。
キーボード選択値をテキストフィールドに設定
キーボードでのボタン選択で、テキストフィールドに値をセットするためには、カスタムキーボードのビューコントローラでボタンの処理を実装する。例えばこのようになる(テキストフィールドのプロパティをキーボードのビューコントローラ側に持たせるのはあまり良いやり方ではない気がするが、とりあえずそこは無視)。
まず、CustomKeyboardInputViewController.h で、対象テキストフィールドとボタンの処理を宣言。
#import@interface CustomKeyboardInputViewController : UIViewController { UITextField *tf; } @property (nonatomic, retain) UITextField *tf; -(IBAction) btPressed:(id) sender; @end
CustomKeyboardInputViewController.m で、ボタンの文字列をテキストフィールドにセットする。
#import "CustomKeyboardInputViewController.h" #import "CustomKeyboardTestViewController.h" @implementation CustomKeyboardInputViewController @synthesize tf; -(IBAction) btPressed:(id)sender { // キーボード上のボタン選択値をテキストフィールドにセット UIButton *bt = (UIButton *) sender; [self.tf setText:bt.titleLabel.text]; // キーボードを隠す [self.tf resignFirstResponder]; } @end
カスタムテキストフィールドのメソッドを少し変えておく。
#import "CustomTextField.h" #import "CustomKeyboardInputViewController.h" @implementation CustomTextField - (UIView *)inputView { CustomKeyboardInputViewController *vc = [[CustomKeyboardInputViewController alloc] initWithNibName:@"CustomKeyboardInputView" bundle:nil]; vc.tf = self; // これを追加 return vc.view; } - (void)dealloc { [super dealloc]; } @end