iOS 7からViewは全画面表示がデフォルトになりました。今回はその理解と対応について。

  • iOS 6 / 7両方対応の記事はよくみかけるので、本記事ではXcode 5でiOS 7以降のみ対応することを前提にして書きます。
  • StoryboardやAuto Layoutの使い方の話は本筋ではないので割愛しています。
  • Auto Layoutについては、こちらの記事を参考にしてください。

サンプルコード: https://github.com/stack3/iOS7FullScreenViewSamples

ViewとStatusBar/NavigationBar/Toolbarの構成

iOS 7以前

01

StatusBar、NavigationBarとToolbarの間にViewが表示されていました。

iOS 7から

02

iOS 7からはViewの上にStatusBar、NavigationBar、Toolbarが重なる形になります。またStatusBar、NavigationBar、Toolbarはデフォルトで半透明であり、透けてViewが見えるようになっています。

全画面表示によって以前と何が異なるのか?

iOS 7で単純にViewの上端(Y = 0)にSubviewを貼り付けると、StatusBarやNavigationBarの下に表示されて見えなくなってしまいます(実際は半透明なのでうっすら透けて見えますが)。Viewの下端にSubviewを貼り付けた場合は、Toolbarが表示されていると、その下に表示されて見えなくなってしまいます。iOS 6のプロジェクトをiOS 7にコンバートする時に起きる多くの弊害もこれが原因です。

全画面対応のベストな方法

最初に書いたように、今回の記事はiOS 7以降のみ対応することを前提とします。その場合、一番簡単に全画面対応する方法は、StoryboardとAuto Layoutを使うことです。

従来のViewController + xibの構成はおすすめできません。Auto Layoutを使ってもSubviewがStatusBarやNavigationBarの下になる問題に悩まされるでしょう。解決する方法もあるのですが面倒です(これは後述します)。iOS 7以前も動作対応する場合や、iOS 7以前のxibファイルをできるだけ修正せずに対応したい場合は別ですが、iOS 7から開発を始める場合はStoryboardを使ったほうが簡単で確実です。

Storyboardを使うことに抵抗がある人へ

以下ような理由からStoryboardの使用をためらう人がいるかと思います。

  1. 1枚のStoryboardファイルにViewControllerを複数配置すると、目的のViewControllerを探しづらくなる
  2. 1枚のStoryboardファイルで管理すると、チーム開発でコンフリクトが起きやすい
  3. そもそもInterface Builderなんか使いたくない。全部プログラムで書きたい

1と2に関しては問題ありません。ViewControllerとStoryboardを一対一にする組み合わせも可能だからです。従来のViewController + xibの構成から、ViewController + Storyboardの組み合わせに変更すれば良いだけです。

3に関してですが、自分もそういう考えの人間でした。Auto Layoutも便利そうに思いましたが、Xcode 4.6.*では、自分が苦労して設定したConstraintが、少し移動させると消えるなど、メンテナンス性に問題がありました。

しかし、Xcode 5からはConstraintの設定方法などが劇的に改善されました。これからはInterface Builder(Storyboard) とAuto Layoutを積極的に使っていくつもりです。

Xcode 5で新しくなったAuto Layoutについての記事を参考にしてみてください。

StoryboardからViewControllerをオブジェクト化する方法

*.storyboardファイル上に1つだけViewControllerを配置して、以下のようにそれをオブジェクト化します。

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"{storyboardファイル名}" bundle:nil];
STHogeViewController *con = [sb instantiateInitialViewController];

この方法でViewControllerとStoryboardを一対一にして管理できるはずです。

Storyboardを使ったサンプル

では、サンプルを見ながら、どのように全画面対応するか見てみましょう。

サンプルコードをダウンロードしてプロジェクトをXcodeで開きます。

起動すると以下の画面が表示されます。

03

StoryboardとAuto Layoutでレイアウトを作成

先ほど話したように1つのStoryboardファイル(Main.storyboard)で複数のViewControllerを管理するのはやめて、ViewControllerごとにStoryboardを作っています。

今回のViewControllerとStoryboardの組み合わせは以下のようになっています。

  • STFromStoryboardViewController.m
  • STFromStoryboardViewController.h
  • STFromStoryboardViewController.storyboard

STMainViewController.mで以下のようにStoryboardからViewControllerをインスタンス化しています。

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"STFromStoryboardViewController" bundle:nil];
STFromStoryboardViewController *con = [sb instantiateInitialViewController];

さて、どのようにLabelを配置しているか見てみましょう。

STFromStoryboardViewController.storyboardを開きます。

このようにViewControllerが1つだけ配置されています。

11

 

StatusBar下のLabelを選択して、Size Inspectorを開くとConstraintsを確認できます。

10

Top Space to: Top Layout Guideとなっていることに注目してください。この場合、StatusBarの下端をConstraintの起点とします。NavigationBarが表示されている場合は、その下端が起点となります。

Toolbar上のLabelを選択して、Size Inspectorを開くとConstraintsを確認できます。

12

Bottom Space to: Bottom Layout Guideとなっていることに注目してください。この場合、Toolbarが表示されていれば、その上端をConstraintの起点とします。NavigationBarが表示されている場合は、その下端が起点となります。

右サイドバーを見てみるとViewControllerの下にTop Layout Guide、Bottom Layout Guideという表示があるのを確認できます。

13

自分でLabelを配置してみる

試しに自分でLabelを配置しなおしてみましょう。

2つのLabelを削除します。

14

 

自分でLabelをStatusBarの下に配置します。

15

 

Pinボタンを押して以下のようにConstraintを設定します。

16

 

Top SpaceのConstraintのプルダウンを押してみましょう。

17

このようにデフォルトで、Top Layout Guideが選択されていることを確認できます。current distance = 0というのは、Top Layout Guideからの距離が0を意味します。

Viewの方は上端からの距離はdistance = 20となっています。もし、Top Layout GuideでなくViewを選択してしまうと、単純にViewの上端から20pxの位置に表示されるようになります。StatusBarだけが表示されている場合は問題ないのですが、NavigationBarが表示されている時はNavigationBarの下に隠れてしまいます。

いずれにせよ、通常はTop Layout Guideのままにしておいて大丈夫です。ただし、ScrollViewやTableViewなどはスクロールするものは、Viewにしたほうが良い場合もあります。これに関しては後述します。

Constraintを設定したらAdd 3 Constraintsボタンを押してConstraintを追加します。以下のようになります。

18

 

LabelのBackgroundColorを青にします。

19

 

これで上端のLabel配置は完了です。

20

 

次は下端のLabel配置です。以下のようにLabelをViewの下端に配置します。

21

 

Pinボタンを押して、以下のようにConstraintを設定します。

22

 

Bottom SpaceのConstraintのプルダウンを押してみます。

23

 

デフォルトでBottom Layout Guideにチェックが入っています。これでToolbarが表示される時は、その上端が起点となります。Top Layout Guide同様にViewを選択すると、Toolbarの下に隠れてしまうので注意が必要です。

Add 3 Constraintsボタンを押して、Constraintを追加すると以下のようになります。

24

 

先ほどと同じように背景を青に変えて完成です。

25

 

実際に動作させてみてうまく動くことを確認してみましょう。

Main画面のfrom Storyboardを選択します。するとSTFromStoryboardViewControllerがオブジェクト化されてモーダル表示されます。

04

単なるモーダルなのでNavigationBar、Toolbarが表示されません。青いLabelがStatusBarの下とViewの下端に表示されています。

横画面も同じようにLabelが表示されます。

05

Closeボタンを押して閉じて、Main画面へ戻り今度はfrom Storyboard with NavigationBar and Toolbarを押してみましょう。

今度は、STFromStoryboardViewControllerがオブジェクト化されてNavigationControllerにPushされます。

06

今度はNavigationBarが表示されています。またToolbarも表示するようにしています。青いLabelがNavigationBarの下とToolbarの上に表示されています。

横画面も同じようにLabelが表示されます。

07

STFromStoryboardViewController.storyboardでは、NavigationBarの表示は考慮せず、StatusBarの下に配置していたことを思い出してください。Top Layout Guide、Bottom Layout Guideに従って、上端、下端のSubviewが配置されていると、NavigationBarやToolbarが表示される場合、されない場合、両方対応できます。仕様変更があってもStoryboard上のレイアウトを修正することなく対応できて良いと思います。

ちなみにViewControllerのAttributes InspectorのSimulated Metricsを以下のようにすると、NavigationBarを表示したときの見栄えをシミュレートすることもできます。

26

27

このSimulated Metricsは、あくまでInterface Builder上で見栄え確認するためのものなので、実際にNavigationBarが表示されるかどうかは関係ありません。特に使う必要はないと思います。Layout GuideとConstraintの設定がうまくいっていないと、どのみち正しく表示できないからです。

その2へつづく