スタックビュー


以下のレシピは、スタックビューを使用して、複雑さが増すレイアウトを作成する方法を示しています。スタックビューは、ユーザインターフェイスをすばやく簡単に設計するための強力なツールです。それらの属性により、配置されたビューのレイアウト方法を高度に制御できます。これらの設定を追加のカスタム制約で拡張できます。ただし、これによりレイアウトが複雑になります。


これらのレシピのソースコードを表示するには、 Auto Layout Cookbook (自動レイアウトレシピ集) プロジェクトを参照してください。


簡単なスタックビュー


このレシピは、単一の垂直スタックビューを使用して、ラベル、画像ビュー、およびボタンをレイアウトします。


Simple_Stack_View_Screenshot_2x


ビューと制約


Interface Builder で、垂直スタックビューをドラッグして開始し、花のラベル、画像ビュー、編集ボタンを追加します。次に、図のように制約を設定します。



simple_stack_2x


  1. Stack View.Leading = Superview.LeadingMargin

  2. Stack View.Trailing = Superview.TrailingMargin

  3. Stack View.Top = Top Layout Guide.Bottom + Standard

  4. Bottom Layout Guide.Top = Stack View.Bottom + Standard

属性


属性インスペクタで、以下のスタックビュー属性を設定します。


スタック整列配布間隔
スタックビュー垂直満たす満たす8


次に、イメージビューで以下の属性を設定します。


ビュー属性
イメージビューイメージ(花の画像)
イメージビューモードアスペクトフィット


最後に、サイズインスペクタで、画像ビューの内容が保持する圧縮耐性 (CHCR) の優先順位を設定します。


名前水平が保持する垂直が保持する水平の抵抗垂直の抵抗
イメージビュー250249750749


議論


スタックビューをスーパービューに固定しなければなりませんが、それ以外の場合、スタックビューは他の明示的な制約なしにレイアウト全体を管理します。


このレシピでは、スタックビューはスーパービューを小さな標準マージンで埋めています。配置されたビューは、スタックビューの境界を満たすようにサイズ変更されます。水平方向に、各ビューはスタックビューの幅に合わせて引き伸ばされます。垂直方向では、ビューはその CHCR の優先順位に基づいて拡大されます。画像ビューは常に利用可能なスペースを満たすために縮小および拡大する必要があります。したがって、その垂直方向のコンテンツにぴったりで圧縮耐性の優先順位は、ラベルとボタンのデフォルトの優先順位よりも低くなければなりません。


最後に、画像ビューのモードをアスペクトフィットに設定します。この設定により、画像のアスペクト比を維持したまま、画像ビューの境界内に収まるように画像ビューで画像のサイズが変更されます。これにより、スタックビューは、イメージを歪めることなく、イメージビューを任意にサイズ変更できます。


スーパービューを埋めるためにビューを固定する方法の詳細については、属性適応するシングルビュー を参照してください。


入れ子になったスタックビュー


このレシピは、入れ子になったスタックビューの複数のレイヤーからビルドされた複雑なレイアウトを示しています。ただし、この例では、スタックビューは必要な動作だけを作成することはできません。代わりに、レイアウトをさらに調整するために追加の制約が必要です。



Nested_Stack_Views_Screenshot_2x



ビュー階層がビルドされたら、次のセクション ビューと制約 に示す制約を追加します。


ビューと制約


入れ子になったスタックビューで作業する場合、内側から外側へ作業するのが最も簡単です。まず、Interface Builder で名前の行をレイアウトします。ラベルとテキストフィールドを正しい相対位置に配置し、両方を選択して、[エディタ(Editor)] > [埋め込み(Embed In)] > [スタックビュー(Stack View)] メニュー項目をクリックします。これにより、行の水平スタックビューが作成されます。


次に、これらの行を水平に配置して選択し、[エディタ] > [埋め込み] > [スタックビュー] メニュー項目をもう一度クリックします。これにより、行の水平スタックが作成されます。次に示すように、インターフェースのビルドを続けます。



nested_stack_views_2x



  1. Root Stack View.Leading = Superview.LeadingMargin

  2. Root Stack View.Trailing = Superview.TrailingMargin

  3. Root Stack View.Top = Top Layout Guide.Bottom + 20.0

  4. Bottom Layout Guide.Top = Root Stack View.Bottom + 20.0

  5. Image View.Height = Image View.Width

  6. First Name Text Field.Width = Middle Name Text Field.Width

  7. First Name Text Field.Width = Last Name Text Field.Width


属性


各スタックには独自の属性の設定があります。これらは、スタックがそのコンテンツをどのようにレイアウトするかを定義します。属性インスペクタで、以下の属性を設定します。


スタック整列配布行間
ファーストネーム水平最初のベースライン満たす8
ミドルネーム水平最初のベースライン満たす8
ラストネーム水平最初のベースライン満たす8
名前の行垂直満たす満たす8
上部水平満たす満たす8
ボタン水平最初のベースライン均一に満たす8
ルート垂直満たす満たす8


さらに、テキストビューの背景色をライトグレーにします。これにより、向きが変わったときにテキストビューのサイズがどのように変更されるかを簡単に確認できます。


ビュー属性
テキストビュー背景ライトグレー


最後に、CHCR の優先順位は、利用可能なスペースを満たすために拡大すべきビューはどれかを定義します。サイズインスペクタで、以下の CHCR 優先順位を設定します。


名前横抱き垂直抱き水平抵抗垂直抵抗
イメージビュー2502504848
テキストビュー250249250250
ファースト、ミドル、
ラストネームのラベル
251251750750
ファースト、ミドル、
ラストネームの
テキストフィールド
48250749750


議論


このレシピでは、スタックビューが連携してほとんどのレイアウトを管理します。ただし、必要な動作をすべて自分で作成することはできません。たとえば、画像ビューのサイズが変更されても、画像はその縦横比 (aspect ratio) を維持する必要があります。残念ながら、簡単なスタックビュー で使用されているテクニックはここでは機能しません。レイアウトは、画像の末端と下端の両方に近づける必要があり、アスペクトフィットモードを使用すると、これらの寸法のいずれか 1 つに余白が追加されます。幸い、この例では、画像のアスペクト比は常に正方形であるため、画像を画像ビューの境界に完全に塗りつぶし、画像ビューを 1:1 のアスペクト比に制約できます。


注意:

Interface Builder では、アスペクト比の制約は、単にビューの高さと幅の間の制約です。Interface Builder は、さまざまな方法で制約の乗数を表示することもできます。通常、アスペクト比の制約については、比として表示されます。したがって、View.Width = View.Height 制約は 1:1 のアスペクト比として表示されます。




さらに、すべてのテキストフィールドは同じ幅でなければなりません。残念ながら、それらはすべて個別のスタックビューにあるため、スタックはこれを管理できません。代わりに、等しい幅の制約を明示的に追加しなければなりません。


簡単なスタックビューと同様に、CHCR の優先順位の一部も変更しなければなりません。これらは、スーパークラスの境界が変化したときにビューがどのように縮小および拡大するかを定義します。


垂直方向に、テキストビューを拡張して、上部スタックとボタンスタックの間のスペースを埋めます。したがって、テキストビューの垂直コンテンツハグは、他の垂直コンテンツハグの優先順位よりも低くなければなりません。


水平方向に、ラベルは本来のコンテンツサイズで表示され、テキストフィールドは余白を埋めるためにサイズ変更されます。デフォルトの CHCR 優先順位は、ラベルに適しています。Interface Builder はすでにコンテンツハグを 251 に設定しており、テキストフィールドよりも高くなっています。ただし、テキストコフィールドの水平コンテンツハグと水平圧縮抵抗の両方を低くする必要があります。


画像ビューは、名前行を含むスタックと同じ高さになるように縮小する必要があります。ただし、スタックビューはコンテンツを緩くハグするだけです。これは、画像ビューの垂直方向の圧縮抵抗が非常に低くなければならないことを意味し、スタックビューを拡張する代わりに、画像ビューを縮小します。さらに、画像ビューのアスペクト比の制約は、垂直方向と水平方向の制約が相互作用するため、レイアウトが複雑になります。つまり、テキストフィールドの水平コンテンツのハグも非常に低くしなければなりません。そうしないと、画像ビューの縮小が妨げられます。どちらの場合も、優先順位を 48 以下の値に設定します。


動的スタックビュー


このレシピは、実行時にスタックに項目を動的に追加および削除する方法を示しています。スタックへのすべての変更はアニメーション化されます。さらに、スタックビューはスクロールビュー内に配置されるため、リストが長すぎてスクリーンに収まらない場合でもリストをスクロールできます。


dynamic_stack_view_screenshot_2x


注意:

このレシピは、スタックビューを動的に操作すること、およびスクロールビュー内のスタックビューを操作することを示すことのみを目的としています。実際のアプリでは、このレシピの動作は代わりに UITableView クラスを使用して実装する必要があります。一般に、スクラッチでビルドされたテーブルビュークローンを実装するためだけに動的スタックビューを使用しないでください。代わりに、他の技術を使用して簡単にビルドできない動的なユーザーインターフェイスを作成するためにそれらを使用してください。




ビューと制約


最初のユーザーインターフェイスは非常に単純です。シーンにスクロールビューを配置し、シーン全体を満たすようにサイズを変更します。次に、スタックビューをスクロールビュー内に配置し、項目の追加ボタンをスタックビュー内に配置します。すべての準備が整ったら、以下の制約を設定します。


dynamic_stack_view_2x


  1. Scroll View.Leading = Superview.LeadingMargin

  2. Scroll View.Trailing = Superview.TrailingMargin

  3. Scroll View.Top = Superview.TopMargin

  4. Bottom Layout Guide.Top = Scroll View.Bottom + 20.0

  5. Stack View.Leading = Scroll View.Leading

  6. Stack View.Trailing = Scroll View.Trailing

  7. Stack View.Top = Scroll View.Top

  8. Stack View.Bottom = Scroll View.Bottom

  9. Stack View.Width = Scroll View.Width



属性


属性インスペクタで、以下のスタックビュー属性を設定します。



スタック整列配布行間
スタックビュー垂直満たす均一行間0


コード


このレシピでは、項目をスタックビューに追加したり、スタックビューから削除したりするために、少しだけコードが必要です。スクロールビューとスタックビューの両方のアウトレットを使用して、シーンのカスタムビューコントローラを作成します。


     1  class DynamicStackViewController: UIViewController {
     2
     3     @IBOutlet weak private var scrollView: UIScrollView!
     4     @IBOutlet weak private var stackView: UIStackView!
     5
     6         // Method implementations will go here...
     7
     8  }
    


次に、viewDidLoad メソッドをオーバーライドして、スクロールビューの初期位置を設定します。スクロールビューのコンテンツがステータスバーの下から始まるようにします。


     1   override func viewDidLoad() {
     2        super.viewDidLoad()
     3
     4        // setup scrollview
     5        let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
     6        scrollView.contentInset = insets
     7        scrollView.scrollIndicatorInsets = insets
     8
     9  }
    

次に、項目追加ボタンのアクションメソッドを追加します。


     1    // MARK: Action Methods
     2
     3   @IBAction func addEntry(sender: AnyObject) {
     4
     5        let stack = stackView
     6        let index = stack.arrangedSubviews.count - 1
     7        let addView = stack.arrangedSubviews[index]
     8
     9        let scroll = scrollView
    10        let offset = CGPoint(x: scroll.contentOffset.x,
    11		                             y: scroll.contentOffset.y + addView.frame.size.height)
    12
    13        let newView = createEntry()
    14        newView.hidden = true
    15        stack.insertArrangedSubview(newView, atIndex: index)
    16
    17        UIView.animateWithDuration(0.25) { () -> Void in
    18            newView.hidden = false
    19            scroll.contentOffset = offset
    20        }
    21    }
    


このメソッドは、スクロールビューの新しいオフセットを計算してから、新しいエントリビューを作成します。エントリビューが非表示に成り、スタックに追加されます。非表示のビューは、スタックの外観やレイアウトに影響を与えないため、スタックの外観は変更されないままです。次に、アニメーションブロックでビューが表示され、スクロールオフセットが更新されて、ビューの外観がアニメーション化されます。


エントリを削除する同様のメソッドを追加します。ただし、addEntry メソッドとは異なり、このメソッドは Interface Builder のどのコントロールにもリンクされていません。代わりに、ビューが作成されると、アプリは各エントリビューをこのメソッドにプログラムでリンクします。


     1   func deleteStackView(sender: UIButton) {
     2        if let view = sender.superview {
     3            UIView.animateWithDuration(0.25, animations: { () -> Void in
     4                view.hidden = true
     5            }, completion: { (success) -> Void in
     6                view.removeFromSuperview()
     7            })
     8        }
     9  }
    


このメソッドは、アニメーションブロック内のビューを非表示にします。アニメーションが完了すると、ビューはビュー階層から削除されます。これにより、スタックの配置されたビューのリストからビューが自動的に削除されます。


エントリビューはどのビューでもかまいませんが、この例では、日付ラベル、ランダムな 16 進文字列を含むラベル、削除ボタンを含むスタックビューを使用しています。


     1   // MARK: - Private Methods
     2   private func createEntry() -> UIView {
     3        let date = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .ShortStyle, timeStyle: .NoStyle)
     4        let number = "\(randomHexQuad())-\(randomHexQuad())-\(randomHexQuad())-\(randomHexQuad())"
     5
     6        let stack = UIStackView()
     7        stack.axis = .Horizontal
     8        stack.alignment = .FirstBaseline
     9        stack.distribution = .Fill
    10        stack.spacing = 8
    11
    12        let dateLabel = UILabel()
    13        dateLabel.text = date
    14        dateLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
    15
    16        let numberLabel = UILabel()
    17        numberLabel.text = number
    18        numberLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
    19
    20        let deleteButton = UIButton(type: .RoundedRect)
    21        deleteButton.setTitle("Delete", forState: .Normal)
    22        deleteButton.addTarget(self, action: "deleteStackView:", forControlEvents: .TouchUpInside)
    23
    24        stack.addArrangedSubview(dateLabel)
    25        stack.addArrangedSubview(numberLabel)
    26        stack.addArrangedSubview(deleteButton)
    27
    28        return stack
    29  }
    30
    31    private func randomHexQuad() -> String {
    32        return NSString(format: "%X%X%X%X",
    33                        arc4random() % 16,
    34                        arc4random() % 16,
    35                        arc4random() % 16,
    36                        arc4random() % 16
    37            ) as String
    38  }
    39  }
    


議論


このレシピが示すように、実行時にスタックビューに対してビューを追加または削除できます。スタックのレイアウトは、配置されたビューの配列に対する変更を補正するために自動的に調整されます。ただし、覚えておくべき重要な点がいくつかあります。


このレシピはまた、スクロールビューで自動レイアウトを使用するアイデアも紹介しています。ここでは、スタックとスクロールビューの間の制約により、スクロールビューのコンテンツ領域のサイズが設定されます。等幅制約は、スタック (およびコンテンツサイズ) を明示的に設定して、スクロールビューを水平方向に埋めます。垂直方向では、コンテンツサイズはスタックの埋めるサイズに基づいています。スタックビューは、ユーザーがエントリをもっと追加するにつれて長くなります。コンテンツが多すぎてスクリーンに収まらない場合、スクロールが自動的に有効になります。


詳細については、スクロールビューの操作 を参照してください。


前:Interface Builder での制約の操作 次:簡単な制約
































































目次
Xcode の新機能

  • 始めましょう

  • 自動レイアウトガイド全メニュー

  • 自動レイアウトレシピ集

  • スタックビュー
  • 簡単なスタックビュー
    属性
    議論
    入れ子になったスタックビュー
    ビューと制約
    属性
    議論
    動的スタックビュー
    ビューと制約
    属性
    コード
    議論
  • 簡単な制約
  • 固有のコンテンツサイズのビュー
  • 自動レイアウトのデバッグ

  • 高度な自動レイアウト

  • 付録

  • 改訂記録











  • トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ









    トップへ