ソフトウェアキーボードの表示に追従してUIViewのサイズを変更

UIViewControllerのshouldAutorotateToInterfaceOrientationメソッドをオーバーライドすると、iPhoneを横に傾けたときにUIViewのサイズを自動的に変えて横表示してくれるようになります。

ならばソフトウェアキーボードを表示させたときも自動的にUIViewのサイズを変えてくれる方法はないのか? 探してみたのですが、なかなか見つかりません。どうもUIViewのサイズを自分で変更する必要があるようです。これをやらないと、例えば、全面にUITextViewを貼りつけた状態でソフトウェアキーボードを表示させると、キーボードの背後にUITextViewがまわってしまい全体が見れなくなってしまうので困ります。

キーボードの表示・非表示は、NSNotificationCenterオブジェクトを介して行えます。UIWindowで、下記の定数が定義されています。

  • UIKeyboardWillShowNotification
  • UIKeyboardDidShowNotification
  • UIKeyboardWillHideNotification
  • UIKeyboardDidHideNotification

名前から想像つくように、キーボードが表示される前、表示された後、非表示になる前、非表示になった後を通知するために使われます。

例えば、キーボードが表示された後にkeyboardDidShowメソッド、キーボードが非表示になった後にkeyboardDidHideメソッドを呼び出すには、こんな感じのコードを書きます。実際には、UIViewControllerのviewDidLoadの中で書くことになるでしょう。

[[NSNotificationCenter defaultCenter]
    addObserver:self
    selector:@selector(keyboardDidShow:)
    name:UIKeyboardDidShowNotification
    object:nil];
[[NSNotificationCenter defaultCenter]
    addObserver:self
    selector:@selector(keyboardDidHide:)
    name:UIKeyboardDidHideNotification
    object:nil];

このようにすると、keyboardDidShowメソッドでは、受け取ったNSNotificationオブジェクトのuserInfoを介して様々な情報を取得することができます。例えばキーボードが表示された後のサイズは、UIKeyboardFrameEndUserInfoKeyキーを指定して取得できます。ただし、ここで得られた座標は、convertRect:fromWindow:メソッドを使ってWindowの座標に変換する必要があります。さらに、UINavigationControllerを使っていてツールバーを下部に表示している場合にはそのサイズも考慮する必要があります。具体的には、こんな感じになりますが実際にはアプリケーションごとに変わってくると思います。

- (void)keyboardDidShow:(NSNotification *)aNotification
{
    CGRect keyboardRect = [self.view
        convertRect:[[[aNotification userInfo]
                      objectForKey:UIKeyboardFrameEndUserInfoKey]
                     CGRectValue]
        toView:nil];
    CGRect viewRect = self.view.frame;
    viewRect.size.height -= (keyboardRect.size.height
        - self.navigationController.toolbar.frame.size.height);
    self.view.frame = viewRect;
}

keyboardDidHideメソッドもほとんど同じです。上記ではviewRectからキーボードで隠れる分を引いていますが、keyboardDidHideメソッドではそれを逆に足すだけです。

通知が不要になったら、忘れずに登録を解除しましょう。viewDidUnloadなどに書いておけばよいでしょう。

[[NSNotificationCenter defaultCenter]
    removeObserver:self
    name:UIKeyboardDidShowNotification
    object:nil];
[[NSNotificationCenter defaultCenter]
    removeObserver:self
    name:UIKeyboardDidHideNotification
    object:nil];

以上で、キーボードに追従してUIViewのサイズが変わるようになります。画面を回転しても、そのたびにキーボードの非表示→表示の通知が来るので、適切にUIViewのサイズが変更されます。