キーボードの位置や大きさを取得する : Objective-C プログラミング

PROGRAM


ソフトウェアキーボードの位置や大きさを取得する

iPhone や iPad では、テキスト入力をする際に、ソフトウェアキーボードが表示されてくるようになっています。

そのため、iPhone アプリや iPad アプリを作るときには、キーボードの表示状態を考慮して、プログラムを組む必要に迫られる場合もよくあります。

たとえば、登場したキーボードによってコントロールが隠されてしまうような場面では、隠れて欲しくないコントロールを移動したりして見えるようにする必要がありますけど、それを実現できるように、キーボードが表示される位置やその大きさを、プログラムで取得することが出来るようになっています。

キーボードの位置やサイズを取得する

キーボードの表示される位置や大きさを取得するには、通知センターから、キーボードの表示状態の変化を知らせる通知を受け取る必要があります。

通知には "UIKeyboardWillShowNotification", "UIKeyboardDidShowNotification", "UIKeyboardWillHideNotification", "UIKeyboardDidHideNotification" がありますが、取得方法はどれも一緒です。

どのタイミングでキーボードの状態を取得したいかで、実装する通知が変わってくる感じです。

 

たとえば、UIKeyboardWillShowNotification 通知から keyboardWillShow: メソッドが呼び出されるように NSNotificationCenter に登録するとします。

このとき、通知センターへの登録は次のような感じになります。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

このコードをどこか適切なタイミングへ、たとえば viewWillAppear などへ記載します。通知を受け取る必要がなくなったタイミングで NSNotificationCenter の removeObserver メソッドも呼ぶようにします。

 

そして、キーボードの位置とサイズの取得は次のようにします。

-(void)keyboardWillShow:(NSNotification*)note

{

// キーボードの表示開始時の場所と大きさを取得します。

CGRect keyboardFrameBegin = [[note.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];

 

// キーボードの表示完了時の場所と大きさを取得します。

CGRect keyboardFrameEnd = [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

 

}

ソフトウェアキーボードはスライドして表示されてくるので、その最初の場所と最後の場所とを、それぞれ UIKeyboardFrameBeginUserInfoKey と UIKeyboardFrameEndUserInfoKey とで取得できる感じです。

処理の際には必要なほうを取得すれば大丈夫です。

 

通常、キーボードが表示されていない状態から、表示させた場合には、UIKeyboardFrameBeginUserInfoKey の方には、キーボードが画面外に表示されるように位置が設定されています。サイズについてはどちらも同じになっています。

キーボードの種類が変更されたとき

また、キーボード表示中にキーボードの種類が切り替わった場合、以前のキーボードと新しいキーボードとで大きさが異なる場合には、再び "UIKeyboardWillShowNotification" と "UIKeyboardDidShowNotification" が通知されるようでした。

Hide 関係の通知は来ないところに注意が必要です。

 

このときのキーボードの位置とサイズは、UIKeyboardFrameBeginUserInfoKey には切り替え前のキーボードの位置とサイズが、UIKeyboardFrameEndUserInfoKey には切り替え後の位置とサイズが、取得できるようになっているようでした。

デバイスが回転した場合の位置やサイズ

なお、デバイスを縦方向(ホームボタンが下)で使っている場合には特に問題ないのですけど、デバイスを回転させた場合には、キーボードの座標が見た目とは違ってくるので注意が必要です。

 

デバイスがどんな向きであっても、キーボードの座標はホームボタンが下になっている場合の座標で取得される感じです。

そのため、たとえばキーボードの高さを取得したい場合に、デバイスが縦の場合には取得したサイズの高さを見ればいいのですけど、デバイスが横だった場合には、取得したサイズの幅を見ないと、実際の高さにならないところに注意します。

 

そのあたりを試して整理してみると、iPhone 4S + iOS 5.0 では、次のような感じの値が取得できました。

デバイスの向き 表示開始位置
(FrameBegin)
表示終了位置
(FrameEnd)
キーボードサイズ 見た目上の
表示完了位置とサイズ
方向 ホームボタン
の位置
x y x y width height x y width height
0 480 0 264 320(水平) 216(垂直) 0 264 320 216
320 0 158 0 162(垂直) 480(水平) 0 158 480 162
0 -216 0 0 320(水平) 216(垂直) 0 264 320 216
-162 0 0 0 162(垂直) 480(水平) 0 158 480 162

このとき、ユーザーインターフェイスが回転されていた場合、ユーザーインターフェイスは必ず左上が (x=0, y=0) になるはずです。

ソフトウェアキーボードは画面の下に表示されるので、そうなると例えば、ホームボタンが右の横方向の場合のキーボード表示完了位置が (x=0, y=0) に、すなわち上方になっています。このことからも、座標系が違っているのが判ります。

 

これを考慮して、座標系を考慮してキーボードの座標を取得するプログラムを組むと、次のような感じになると思います。

+ (CGRect)keyboardRectByNotification:(NSNotification*)note userInfoKey:(NSString*)key orientation:(UIInterfaceOrientation)orientation

{

CGRect result;

 

CGRect keyboardFrame = [[[note userInfo] objectForKey:key] CGRectValue];

CGRect keyWindowFrame = [[[UIApplication sharedApplication] keyWindow] frame];

 

CGFloat keyWidth = CGRectGetWidth(keyWindowFrame) - CGRectGetWidth(keyboardFrame);

CGFloat keyHeight = CGRectGetHeight(keyWindowFrame) - CGRectGetHeight(keyboardFrame);

 

// キーボードの座標系をビューの座標系に変換します。

switch (orientation)

{

case UIInterfaceOrientationPortrait:

result = keyboardFrame;

break;

 

case UIInterfaceOrientationPortraitUpsideDown:

result.origin.x = keyboardFrame.origin.x;

result.origin.y = keyHeight - keyboardFrame.origin.y;

result.size = keyboardFrame.size;

break;

 

case UIInterfaceOrientationLandscapeLeft:

result.origin.x = keyboardFrame.origin.y;

result.origin.y = keyboardFrame.origin.x;

result.size.width = keyboardFrame.size.height;

result.size.height = keyboardFrame.size.width;

break;

 

case UIInterfaceOrientationLandscapeRight:

result.origin.x = keyboardFrame.origin.y;

result.origin.y = keyWidth - keyboardFrame.origin.x;

result.size.width = keyboardFrame.size.height;

result.size.height = keyboardFrame.size.width;

break;

}

 

return result;

}

たとえばこのようなメソッドを作成して、通知センターから渡された NSNotification オブジェクトと、取得したいキーボードの情報 ("UIKeyboardFrameBeginUserInfoKey" または "UIKeyboardFrameEndUserInfoKey") と、現在のビューの回転状態を渡します。

そうすることで、どの方向にデバイスを回転させても、そのときに見えるのと同じ座標系で、キーボードの位置やサイズを取得することが出来るようになりました。

iPad + iOS 5 の分割キーボード

iPad + iOS 5 から利用可能となった分割キーボードの場合、キーボードが分割されたタイミングで "UIKeyboardWillHideNotification" と "UIKeyboardDidHideNotification" とが通知されるようでした。

事実上はキーボードが隠れるわけではないのですけど、Hide 関係の通知が来て、分割キーボードを標準キーボードに戻すまでは Show 関係の通知は来ない感じです。

しかも、キーボードは表示されているのに、キーボードの位置と大きさは通常キーボードが隠れたときと同じに取得されるため、分割キーボードでの動作の際にはそのあたりに十分に注意して、プログラムを制御する必要がある感じでした。

[ もどる ]