iOS7対応の話。
やはりお前らのiOS7対応は間違っている(變) - Qiita [キータ]
ざっくり要約すると、「iOS7向けにアプリを作り直して、iOS6対応するのが真のiOS7対応である」というごもっともなお話。
フラットデザインに合わせてデザイナーに再依頼して、DevPreview版のXCodeと英語リファレンスと格闘する余裕を与えてくれるような時間と予算が振ってくるならそうですよねー、という感じ。
iOS4時代に作成されたそれなりのコード量のあるレガシーなアプリを1から作り直す勢いでリファクタリングさせてくれる環境とか、プライベートな時間を使って新しいiOS SDKの知識をガンガン身に着けてくれるような超人だらけの環境とか、毎年OSのバージョンアップに合わせて再教育してくれるような余裕のある環境なら、正しいのかもしれません。
以下、最近Oracle周りしかやってない人間による記述になります。消費税増税怖い。
Extend Edges
edgesForExtendedLayoutを良く分からず使っている人が多い気がします。
これはたぶん、Extend Edgesの概念について理解する前提となる、「ViewControllerの管理するView領域」を把握していないのが原因だと思っています。
というのも、iOS5~6から入っているとその存在自体、認識する機会がないので。
本来、UIViewControllerのプロパティviewを画面のどこに表示するのかを、UIWindowに対して教える必要があります。といっても、特別なことをしてるわけじゃなくて、UIViewControllerのview.frameをセットした上でWindowに対してaddSubView:するだけです。
iOS4辺りまではメインのWindowのサイズを取得して、そこからステータスバー分20ptを引く、というようなコードを自前で記述する必要がありました。
しかしUINavigationController等を経由したり、iOS5で追加されたrootViewControllerを用いると、適切なframeを自動的に設定してくれるため、自作したUIViewControllerの管理するView領域について、明示的に記述する必要がなくなりました。
Windowに表示される際に、誰かがframeを設定しているんだ、ということさえ認識してしまえば、Extend Edgesの理解は容易だと思います。
Extend Edgesそのものは本当に単純で、設定されたUIViewControllerのview.frameを、UIEdgeInsetsで指定した分だけ拡張するというものです。「拡張」と呼称するとview.frameに対して追加の領域が与えられる印象がありますが、view.frameそのものの位置とサイズが変更されます。
XCode5でビルドした場合、NavigationController直下のUIViewControllerでは、ステータスバーとナビゲーションバー分(64pt)拡張された設定がデフォルトとなっているため、64pt分のズレが生じるのです。
ViewControllerの管理するView領域の違い
iOS6と7ではこの自動設定されるView領域(frame)が状況によって異なるので、微妙な分かりづらさを生んでいます。
rootViewControllerに対して、独自のUIViewControllerを設定した場合、iOS6ではstatusBar分を自動的に間引いた領域が設定されていましたが、iOS7ではstatusBarを含む画面全体がView領域となります。
対して、UINavigationControllerやUITabBarControllerを設定し、独自のUIViewControllerを設定した場合、iOS6/7でのView領域は同一(UINavigationBarなどバーの部分を除いた領域)です。
ただし前述した通り、領域拡張がデフォルトとなっているため、ナビゲーションバーやステータスバーまで実際のコンテンツ領域が拡張されます。この領域拡張範囲を変更する設定が、Under Top Bars設定であり、edgesForExtendedLayoutプロパティです。
| パターン | ズレの原因 | 対処方法 |
|---|---|---|
rootViewControllerに独自のViewControllerを設定した |
View領域の違いによる20ptのずれ | UI部品の位置を20ptズラす |
NavigationController経由でViewControllerを設定した |
edgesForExtededLayoutが設定されていることによる、64ptのずれ |
edgesForExtendedLayoutにUIRectEdgeNoneを設定し領域拡張を無効にする。もしくはUI部品の位置を64ptズラす |
AutoLayoutの利用
AutoLayoutで画面を構築する場合、Top Layout Guideを利用することで、ステータスバーやナビゲーションバーからの距離でUI部品を配置できます。
iOS7のためにコンポーネントの再配置が可能で、かつiOS5(AutoLayout利用不可)を切れるなら、Top Layout Guideを使えばいいので、iOS6/7 Deltasよりも推奨された方法になるかと思います。
重箱の隅
背景に何もビューがないことから真っ黒な色に対してすりガラス表現が適用されている
この説明は厳密には間違いです。
iOSではUIWindowもUIViewのサブクラスなので黒いビューが存在している、が正しいかと。
ずれているのはiOS7から考え方が全画面表示になったからで、それに伴ってView上のコンポーネントを調整しましょう。
「考え方が全画面表示になったから」はずれている理由ではないと思います。
このケースでずれているのは、単にedgesForExtededLayoutプロパティによる領域拡張がデフォルトで設定されているから、というだけの話です。
「領域拡張を無効化することで、過去のコードと互換性を保つ」というiOS7対応方法が間違っている説明にもなっていません。
マイナーアップデートでナビゲーションバーがデフォルトで不透過になった今なら尚更で、敢えてiOS7用にコンポーネントを再配置するのは、半透明(blur表現)を復活させる必要がある場合だけでいいような気がします。
UIScrollView系はInsetsによってスクロール開始点をずらす
contentInsetはスクロール開始点をずらす、というより単に「余白を設定する」と説明した方が分かりやすいと思います。
ちなみに、Adjust Scroll View Insetsは単にedgesForExtededLayoutによって拡張した領域分を、contentInsetによる余白で相殺するというだけの設定です。
それを理解していれば、UIViewControllerのviewプロパティがUIScrollView系統(UITableViewはUIScrollViewのサブクラス)のときのみ有効なのも自明かと思います。