乗数が 1.0 でない場合、中心の制約が何を意味するのかを理解するのは難しいです。私は Xcode 6 でいくつかの実験を行いましたが、これが私の結論です。
問題の制約の形式A.center.x = B.center.x * m + c
は です。A
とB
は関係するビュー、m
は制約の乗数、c
は制約の定数です。
center.x
Bが他の制約によって固定されていると仮定しましょう。次に、自動レイアウトがこのアルゴリズムを使用したかのように動作すると思います。
A と B の最も近い共通の祖先ビューを見つけます。この共通の祖先を G と呼びます。
G の座標系で bxg = Bxcenter とします。としてコードでこれを計算できますCGFloat bxg = [G convertPoint:B.center fromView:B.superview].x
。
axg = G の座標系における A の希望する x 中心を計算します。 CGFloat axg = bxg * m + c
.
axg を の座標系に変換し、A.superview
として保存しA.center.x
ます。
では、「等間隔のビュー」という目標を達成するために、中心の制約をどのように使用すればよいでしょうか? 私たちはしません。
これが問題です。3 つのサブビューがすべて同じ幅 w であるとします。(幅が異なる場合、問題はさらに難しくなります。) そして、コンテナー ビューの幅が W であるとしましょう。中央のサブビューと右側のサブビュー、右側のサブビューの右側に 1 つ)。
したがって、余白の幅は (W - 3 w) / 4 となるはずです。次に、それを何らかの形で別の制約に差し込みます。中央の制約を使用したかったのですが、簡単にするために、左端のビュー L の左端の制約を考えてみましょう。制約を L.left = (W - 3 w) / 4 にする必要があります。この制約は複雑すぎます。直接処理する autolayout。自動レイアウトの制約には 2 つのビュー属性しか関与できませんが、これには 3 つの属性が関与します。
解決策は、スペーサー ビューを導入することです。必要な 3 つのサブビューから始めましょう。
これら 3 つのサブビューのそれぞれを 80x80 で垂直方向の中央揃えに既に制約しています。
ここで、灰色で示されている 4 つのスペーサー ビューを追加します。
各スペーサーの高さと垂直方向の中心を制限しましたが、幅は制限していません。次に行うことは、すべてのスペーサーが同じ幅になるように制約することです。
次に、各スペーサーのリーディング エッジとトレーリング エッジを最も近い隣接するエッジに固定し、手動で定数をゼロに設定します。最初のスペーサーの作り方は次のとおりです。
他の 3 つのスペーサーについても同じことを行います。ここではそれを示しません。
ビュー コントローラーを選択し、Xcode にすべてのフレームを更新するように依頼すると、等間隔のビューが表示されます。
実際には実行時にスペーサーを表示したくないので、スペーサーを選択して非表示に設定します。 非表示のビューは引き続きレイアウトに参加します。
では、サブビューの幅がすべて同じでない場合はどうなるでしょうか? 青いサブビューの幅を変更しましょう:
自動レイアウトは、スペーサーが引き続き同じ幅になるようにフレームを更新します。