2013年4月3日水曜日

iPadのSplit Keyboardに関するあれこれ。

iOS5以降存在するSplit Keyboard(キーボードをスクロールさせると分割するアレ。以下分割キーボードと呼称する)はいろいろ厄介なんだけど、あまりその辺を語っているのを見かけない。

まず、分割キーボードはShowNotificationを通知しない。さらに固定キーボードから分割キーボードに移行すると、HideNotificationを通知する。つまり単純にShowとHideのNotificationでキーボードの表示/非表示判定する方法は使えなくなった。この辺までは常識。

分割キーボードか固定キーボードかを判定するには、Show/HideのNotificationのuserInfoに格納されている、UIKeyboardFrameChangedByUserInteractionの値を利用する。この値が1であれば分割キーボード、0であれば固定キーボード。

しかし「最初から分割キーボードで表示される」場合はそもそもShowNotificationの通知が発行されないため、上記の方法で「出現したキーボードが分割キーボードである」と判定することはできない。(HideNotificationも固定→分割に切り替わったときだけで、最初から分割キーボードとして表示されるときには発行されない)

ではどうやって「分割キーボードが表示された」ことを取得すればいいのか。

それはFrameChangeNotificationを利用することで実現できる。この通知はキーボードのframeに変化が発生した際(表示時/消去時/分割時の移動時)に発行されるもので、iOS5で追加された。このため、iOS4以前との互換性が必要な場合はNSNotificationCenterの購読/解除の処理でバージョン判定を行わなければならない。

また、FrameChangeNotificationは状況に応じてuserInfoに格納する値が変化する点に注意。

Show、HideNotificationと同時に呼ばれたときは、UIKeyboardFrameChangedByUserInteractionを含めた多くの情報を持っているので、UIKeyboardFrameEndUserInfoKeyと合わせることで、キーボードの状態を把握することができる。

単体で呼び出される場合(=分割キーボードの位置変更時)には、will/didそれぞれ一つのframe値のみが格納されている。

  • UIKeyboardFrameChangedByUserInteractionが0であれば固定キーボード、1であれば分割キーボードであると判定。
  • UIKeyboardFrameEndUserInfoKeyのframeが、self.view.windowのframe内に含まれるかを、CGRectContainsRect関数で判定する。キーボード出現/分割キーボード移動であればYES、キーボード消去であればNOが返る。
  • iOS5未満にも対応するのであれば、バージョン判定を行ってiOS5以上はFrameChangeNotificationを、iOS4以下はShow/HideNotificationを受信し、それぞれに処理を書く。
という感じでシンプルに解決できそう。

なお、private API上等ならば、self.view.window.firstResponderをキー値監視してしまうのが手っ取り早い。