質問: VerticalなStackViewの中に置いたViewの左右に10ポイントの空白を設けたいが、Conflicting Constraintsする ↑によって左右に空白を設けることができました。 `StackView`を扱うには中に`View`を置いてさらにその中に部品を配置していけばよいことがわかりました。 そこで、添付画像のようにボタンを置きました。 ボタンの高さは`Intrinsic Content Size`によって自動で決定されると認識しています。 この`Intrinsic Content Size`の高さと`View`の高さを同じにしたいです。 やってみたところ、同じになりましたが意図と違いました。 Viewの高さが決定された後で、そのViewの高さがボタンの高さにに設定されているように感じます。 `内側のボタン`の`サイズ`に基づいて`View`のサイズを決定させてやるにはどうすればよいのでしょうか? --- ![画像の説明をここに入力](https://i.stack.imgur.com/QYXIe.png)
回答: まずUIKitのコンポーネントにはUILabelやUIButton、UIImageViewなどのようにIntrinsic Content Sizeを持つものとUIViewなどIntrinsic Content Sizeを持たないものがあります。 (前者についてもテキストが複数行に渡る場合などは幅を与える必要があるなど細かい違いはいろいろあります) UIButtonは自身のコンテンツ(テキストや画像)に応じてIntrinsic Content Sizeが決まるので原則としてはそれを利用します。そうすると長いテキストであっても自然にサイズと位置が調整されるのでAuto Layoutのメリットが享受できます。 (フォントサイズを小さく設定している場合や、テキストが短いことがわかっている場合(「OK」や「了解」など)はボタンについては小さくなりすぎて押しにくくなるため、あえて幅や高さの制約を与えることはあります。その場合でも最低44pt以上の高さを確保するなどの指定が好ましく、Equal制約ではなくGreaterThan制約を付ける方がいいです。) まずボタンですが、ボタンはコンテンツに応じてIntrinsic Content Sizeを持つので、タテヨコそれぞれ1つ以上の制約があれば全体の制約を満たすことができます。 下のスクリーンショットはボタンに水平・垂直方向についてセンタリングの制約をつけたものです。それだけで制約が満たされていることがわかります。 !画像の説明をここに入力 一方UIViewはIntrinsic Content Sizeを持たないので、タテヨコそれぞれ2つ以上の制約が必要です。一般的には高さと幅を何らかの方法で与える必要があります。 下のスクリーンショットはUIViewに水平・垂直方向についてセンタリングの制約をつけたものです。これだけでは制約が足りないのでエラーが出ています。 !画像の説明をここに入力 制約を満たすためには幅と高さを何らかの方法で決定する必要があります。 制約によって指定する以外にサブビューの大きさによって外側のビューの高さが決まるようにするには、制約が上下・左右の両端に切れ目なく繋がるようにします。 下のスクリーンショットは、上記のビューのサブビューとしてボタンを追加し、ボタンとビューの制約として上下・左右に10ptのマージンを設定したものです。 ビューの制約は先ほどと同様にタテヨコのセンタリングだけですが、ビューのサイズがボタンの幅と高さ(+制約のマージン)によって決定できるのでエラーが消えていることがわかります。ビューの大きさもAuto Layoutによって自動的に最適な大きさになりました。 これが基本です。 !画像の説明をここに入力 今回の例ではそのほか複数の要因によって最終的に制約がどう解決されるのかが変わるので、難しいのですがこの基本を応用することになります。 まず内部の入れ子にしたビューにボタンを置いて、上下・左右方向に切れ目なく繋がるように制約を付けます。わかりやすいように10ptにしていますが、ぴったり同じ大きさにしたい場合は0ptにすればいいです。 ここで一度実行してみてください。今回の場合、高さを決まっているビューが片方のビューだけなので、余った空間をUIStackViewがどのように解決するかはStoryboard上のシミュレーションと異なる場合があります。 他に条件がなければ下記のような見た目の挙動が得られるはずです。 UIStackViewの設定はFill/Fillを想定しています。 !画像の説明をここに入力 もし下記のようにUIStackViewの高さの制約が優先され、ボタンが上下・左右の制約を満たすように拡大された場合、解決方法はいくつかありますが、1つはボタンが拡大しないように優先度を設定します。 !画像の説明をここに入力 ボタンを選択してContent Hugging Priorityを1000(Required)に設定します。 Content Hugging Priorityはコンポーネントの「大きくなりにくさ」を設定します。 !画像の説明をここに入力 これによりボタンのサイズが大きくならない優先度が必須(=1000)なので、ボタンのサイズを維持したまま上下・左右の制約を満たそうとするので、ボタンの大きさは本来のままで、余った領域が拡大する形でレイアウトが解決されます。