Swift Playgroundsで学ぶiOSプログラミング 第68回
VFL(Visual Format Language)とは?
レイアウト専用言語によってAuto Layoutを機能させる
2017年12月18日 17時00分更新
前回から、iOSだけでなく、macOS、そのほかのアップル製品のアプリ開発に共通のレイアウト機能、Auto Layoutを取り上げています。Auto Layoutの目的をひと言で表せば、画面(ウィンドウ)のサイズ(解像度)、向きなどの相違、変化に柔軟に対応するフレキシブルなレイアウト設定を実現することにあります。
前回取り上げたのは、親のビューの中に配置する子のビュー、つまりユーザーインターフェース部品ごとに、拘束(Constraint)をプログラムで設定していく方法でした。その場合、各ビューのほぼ4辺ごとに拘束を設定する必要がありました。プログラムで書いていることが、頭の中で図解的に想像できるようになれば、それなりに直感的な設定方法なのですが、どうしてもコード量は多くなりがちです。これまでにこの連載で使ってきた、ビューのフレームをCGRectで設定する方法のほうがコード量は明らかに少なかったはずです。Swift Playgrounds上の実験的なプログラムなのだから、フレーム設定で十分だという考えも当然あります。
しかし実際のアプリプログラムでは、もっぱらAuto Layoutが使われいるのも事実です。それが手軽に利用できるのは、もちろんInterface Builderのおかげなのですが、Auto Layoutの原理を学習するには、いきなりInterface Builderを使うよりもプログラムで拘束を設定する方法から始めるほうが近道だという気もします。
一方、Auto Layoutには、最初からプログラムによって拘束を設定することを前提にした、別の記述方法もあります。それが今回取り上げるVFL(Visual Format Language)です。その名前が示すように、視覚的、直感的に拘束を記述できるように考えられたものです。前回取り上げた方法が、レイアウト対象のビューを主体としてそこに拘束を付加していくものだったのに対し、VFLでは拘束を主体として、その中で拘束対象のビューを指名するといったかたちになります。
ともあれ、前回の方法とどこが違うのか、どんなメリット、デメリットがあるのか、いろいろな具体例を使って見ていきましょう。
垂直・水平方向の拘束を記号のような言語で別々に設定する
まず、単純な例として、親のビューの4辺から、一定の距離で子のビュー(ここではUILabel)を配置する例を取り上げます。ビューコントローラーや、中に配置するラベルの設定については、前回とほとんど同じなので、説明は省きます。
VFLによる拘束は、垂直方向と水平方向を別々に設定します。まず垂直方向の拘束ですが、ラベルの上辺、下辺ともに、親のビューから200ポイント離した位置に置くとすると、そのVFLは「V:|-200-[label]-200-|」となります。「言語」というには、かなり視覚的で、文字で模式図を書いているようなものです。
まず先頭の「V:」は、垂直方向の拘束を表します。水平方向なら当然「H」です。次の「|」(ASCII記号の縦棒)は、親のビューの辺(最初に出てくるのが上辺)を表しています。そして「-200-」が距離をポイントで表すので、「[label]」で表された子のビューの辺は、親のビューから200ポイント離れた位置に置かれることになります。距離には省略形の「-」もあって、その場合はデフォルトの距離=8ポイントを表します。親のビューと子のビューの間に隙間を空けたくなければ「|[label]」のように書けば、ぴったりくっついて配置されます。その後ろも同様で、子のビューの下辺は、親のビューの下辺から200ポイント離れた位置に置かれることになります。
この説明だけではまだ疑問も残ると思いますが、このVFLを実際に拘束オブジェクトとして作成する部分までのコードを見てみましょう。
VFLによる拘束は、NSLayoutConstraintクラスのconstraintsメソッドで作成します。そのメソッドには、VFLを文字列で与えます。また、VFLに出てくるビューの名前(上の例では「label」)は、辞書によって、名前とビューオブジェクトの対応を指定します。この例では「label」という名前で呼ばれるビューは、label1オブジェクトのことだと指定しています。こうして作成した拘束は、とりあえず配列に入れておきます。
次に、まったく同様にして水平方向の拘束を作成したあと、その拘束も配列に加え、ビューのaddConstraintsメソッドを使って拘束の配列をビュー(ここでは親のビューであるself.view)に適用します。
同じ図で結果も示しましたが、ラベルは親のビューの上下の辺から200ポイントずつ、左右の辺からは100ポイントずつ離れた位置に配置され、同時に大きさも決まっています。これでラベルは上下、左右方向ともに親のビューにセンタリングされているのですが、大きさは親のビューの大きさに依存しています。また、もし親のビューの高さが400ポイント以下、あるいは幅が200ポイント以下の場合には、ラベルの高さや幅がゼロ以下になってしまい、結局表示されないことになります。
このようなレイアウトが有効な例もあるでしょうが、一定以上の大きさを確保したいユーザーインターフェース部品の配置には不向きな場合が多いでしょう。
この連載の記事
- 第100回 SceneKitの物理現象シミュレーションとアニメーションをARKitに持ち込む
- 第99回 「物理学体」と「物理学場」を設定して物理現象をシミュレーション
- 第98回 SceneKitのノードに動きを加えるプログラム
- 第97回 いろいろな形のノードをシーンの中に配置する
- 第96回 SceneKitの基礎シーンビュー、シーン、ノードを理解する
- 第95回 現実世界の床にボールや自動車のモデルを配置する
- 第94回 ARKitを使って非現実世界との融合に備える
- 第93回 ARKitが使えるiPadを識別するプログラム
- 第92回 Swift Playgrounds 2.1での問題点をまとめて解消する
- 第91回 iPadの内蔵カメラで撮影した写真を認識するプログラム
- この連載の一覧へ