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
のサブクラス)のときのみ有効なのも自明かと思います。