iPhoneのステータスバーの高さを取得する【iOS6】

【追記】
このエントリだいぶ古いです。iOS6の時のオハナシ。iOS7以降は挙動変わります(‘A`)
———————————–

IMG_2027
ステータスバーのスタイルをBlackTranslucentにするとViewが画面いっぱいに広がるが、ステータスバーを避けて表示しなければならないものもある。例えば上の画像の左上の電子国土マークがそれ。

ここで、ステータスバーの高さは20ピクセル! と決め打ちで上20ピクセル分を固定値で避けると、インターネット共有中などの時に下のように死亡する。
IMG_2028
で、ステータスバーの高さを正しく取得するには、UIApplicationのstatusBarFrameプロパティをみる。
[UIApplication sharedApplication].statusBarFrame
こいつが {{0, 0}, {320, 20}} とかのCGRectを返してくるのでそのサイズで判定。
iPhoneで縦位置固定の場合は height だけ見ればいいんだけど、この値は画面の回転が反映されないWindow座標系で得られるので回転する場合は向きを考慮する必要がある。
でもUIApplicationのstatusBarOrientationをみたりとか座標を変換したりとかは面倒いので、欲しいのはステータスバーの高さだけなので、幅よりも高さが大きくなることはないと決めつけてheightかwidthのどちらか小さい方をステータスバーの高さとする、ってのが手っ取り早いと思う。(ウンコ判定だけれども、この判定にする理由は下の方にもある)

これで一件落着。

と、思うのはちょっとだけ早い。

テザリングするとステータスバーの高さが変わる。自分のアプリがフォアグランドになってる最中でも、いきなり接続されたり解除されたりして、思わぬタイミングでステータスバーの高さが変わる場合がある。そんな時でもステータスバーの高さが変わったタイミングでそれに合わせた画面表示に変更したい。

どうするか。

そんな時のためのNotificationが用意されているので、Observeすればよい。

こんなカンジ。
UIApplicationWillChangeStatusBarFrameNotificationはステータスバーの高さが変わる直前に通達されて、userInfoで変更後のステータスバーのサイズを得られる。UIApplicationDidChangeStatusBarFrameNotificationはステータスバーの高さが変わった後に通達されて、userInfoで変更前のステータスバーのサイズを得られる。詳しくはUIApplicationのReferenceのNotificationsのあたりを参照のこと。

この2つのNotificationは「ステータスバーのフレームが変化した時」に通達されるので、ステータスバーが太った時だけでなく、画面が回転した時にも通知がやってくる。
この時 WillChange の方を監視する場合は注意が必要で、userInfoには回転後のステータスバーのWindow座標が入っているけど、この通知が来る時点ではまだ回転が始まってないからUIApplicationのstatusBarOrientationなどは回転前の値を返すのでその向きの判定には使えないのだ。
なので、ステータスバーの高さだけ知りたいのならUserInfoで得られる変換後のフレームのheightかwidthか小さい方でいいやみたいな。

このふたつのNotificationはアプリがフォアグランドの時にステータスバーのサイズが変わった場合のみ通達される。バックグランドでステータスバーのサイズが変わった時(例えば設定アプリでインターネット共有を切り、ステータスバーの高さが通常に戻ってからアプリがフォアグランドになった時)にはこの通達はこない。

以上、EnterForegroundだかBecomeActiveだかのタイミングでUIApplicationのstatusBarFrameを確認し、上記いずれか(または両方)のNotificationでフォアグランド時の高さの変更に備える、ってやるとステータスバーの高さを正しく扱えるようになる。

ハズ。