ぽんぽこ日記

プログラミング、読書、日々の生活

全画面表示と透明ステータスバーの関係

iPhoneアプリにおいて、画像の閲覧など、ナビゲーションバーとステータスバーを隠したい場合があります。さらに、ナビゲーションバーとステータスバーを表示しているときも、黒っぽいスモークがかかった透明なスタイルを設定して、画面一杯に画像などコンテンツを表示したい場合が多いと思います。

まず透明化を実現するには、このビューの表示の開始タイミングViewWillAppearの中などで、

    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
    self.navigationController.navigationBar.barStyle = UIBarStyleDefault;

と書けばOKです。

ステータスバーとナビゲーションバーを隠すには、

[[UIApplication sharedApplication] setStatusBarHidden:NO  animated:YES];
[self.navigationController setNavigationBarHidden:NO animated:YES];  

とし、出す場合は、

[self.navigationController setNavigationBarHidden:YES animated:YES];  
[[UIApplication sharedApplication] setStatusBarHidden:YES  animated:YES];

とします。

出す場合と隠す場合では、メソッドの呼び出し順を逆にすることに注意して下さい。
これはどうやら、ナビゲーションバーはステータスバーの表示状態を参照して、自分の表示位置を決めていることに起因するようです。ですので、逆にしないとステータスバーとナビゲーションバーが重なって表示されてしまいます。



実はここからが本題です。ドキュメント通りでは上の通りにすれば良いはずなのですが、iPhone2.2/2.2.1では、実際には下の動画のような動きになってしまいます。

http://dl.dropbox.com/u/6579646/uploads/2009/05/2_2_workaround.swf

動画では、画面上部のステータスバーが表示されていた部分が20.0ピクセル分白く残ってしまって、画像が左上の端から表示されません。これではステータスバーを隠したり透明にする意味がありません。いろいろ試行錯誤した結果、ViewWillAppearとステータスバーを消すときに、下のような回避コードを入れることで解決しました。

  CGRect frame = [[UIScreen mainScreen] bounds];
  self.navigationController.view.frame = frame;
  CGRect r = self.navigationController.navigationBar.frame;
  r.origin.y = 20;
  self.navigationController.navigationBar.frame = r;


ちなみに、iPhone3.0ではこれらの問題は解決されているようですので、回避策は必要ありません。
OSのバージョンはUIDeviceクラスのsystemVersionプロパティで取得できますから、動的に挙動を変更することが可能です。単一バイナリでOSのバージョンに応じて動的に回避策を適用できるでしょう。

なお、このサンプルアプリは、ルートビューの上にUIImageViewとボタン類を乗せている構造になっています。Nibからウインドウ階層を作ると、フレームワークがルートビューの子ビューの構築をする時に、子ビューの原点のY座標をステータスバーの高さの20px分下にずらしてつくるようなので、それを見越してあらかじめ-20pxに設定してあります。