月別アーカイブ: 2011年6月

ソフトウェアキーボードの表示に追従して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のサイズが変更されます。

同一カテゴリー内で前後ナビゲーション

標準のテーマのTwentyTenでは、各投稿ページ内に前後の投稿へ移動できるナビゲーションが付いています。ただし標準では順序がカテゴリーは関係なく全ての投稿を日付順に並べた状態になっています。

このようなルールはカテゴリーを明示的に使っているサイトでは、ちょっと違和感があります。そこで、同一カテゴリー内で前後に移動できるようにリンクを変更するようにしました。

例によって子テーマのfunctions.php内で何とかしたかったんですが、面倒になってきたのでテーマのファイルをそのまま書き換えてしまいます。

loop-single.phpを自作の子テーマにコピーし、previous_post_link関数とnext_post_link関数が使われている部分をこのように書き換えます。

<?php previous_post_link( '%link', '<span class="meta-nav">' .
 _x( '&larr;', 'Previous post link', 'twentyten' ) .
 '</span> %title', true ); ?>
<?php next_post_link( '%link', '%title <span class="meta-nav">' .
 _x( '&rarr;', 'Next post link', 'twentyten' ) .
 '</span>', true ); ?>

要するに、第三引数にtrueを加えるだけです。

これらの関数の第三引数の説明は以下のようになっています。

bool $in_same_cat: Optional. Whether link should be in same category.

そのうち、functions.phpの中だけで完結できるようにしたいな…