UIStackViewに表示可能なビューを追加したとしましょう。どうすればUIStackView
スクロールを作成できますか?
誰かが解決策を探しているのであればコードなし、私は自動レイアウトを使用して、ストーリーボードでこれを完全に行うための例を作成しました。
github から入手できます。
基本的に、例を再現するには:
UIScrollView
を作成し、その制約を設定します。UIStackView
をUIScrollView
に追加しますLeading
、Trailing
、Top
、およびBottom
はUIScrollView
からのものと等しくなければなりません。Width
とUIStackView
の間に等しいUIScrollView
制約を設定します。UIStackView
で、Axis = Vertical、Alignment = Fill、Distribution = Equal Spacing、およびSpacing = 0を設定します。UIViews
に多数のUIStackView
を追加します。AppleのAuto Layout Guideには、 Scroll Viewsの操作 に関する全セクションがあります。いくつかの関連スニペット:
- コンテンツビューの上下左右の端をスクロールビューの対応する端に固定します。コンテンツビューは、スクロールビューのコンテンツ領域を定義します。
- (オプション)水平スクロールを無効にするには、コンテンツビューの幅をスクロールビューの幅と同じに設定します。コンテンツビューはスクロールビューを水平方向に塗りつぶします。
- (オプション)垂直スクロールを無効にするには、コンテンツビューの高さをスクロールビューの高さと同じに設定します。コンテンツビューはスクロールビューを水平方向に塗りつぶします。
さらに:
レイアウトは、コンテンツビューのサイズを完全に定義する必要があります(手順5と6で定義されている場合を除く)。 …コンテンツビューがスクロールビューよりも高い場合、スクロールビューは垂直スクロールを有効にします。コンテンツビューがスクロールビューよりも広い場合、スクロールビューは水平スクロールを有効にします。
要約すると、スクロールビューのコンテンツビュー(この場合はスタックビュー)は、その端およびに固定されている必要があります。制約があります。つまり、スタックビューの内容は、スクロールが必要な方向に(直接または間接に)制限する必要があります。つまり、垂直スクロールスタックビュー内の各ビューに高さの制限を追加することを意味します。以下は、スタックビューを含むスクロールビューの垂直スクロールを可能にする方法の例です。
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
Eikが言うように、UIStackViewとUIScrollViewはうまく連携しています。 here を参照してください。
重要なのは、UIStackViewがさまざまなコンテンツに対して可変のheight/widthを処理し、UIScrollViewがそのコンテンツのスクロール/バウンスをうまく処理することです。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
ここで一番投票された答えの制約は私のために働きました、そして私は私のストーリーボードで作成されたように、下記の制約のイメージを貼り付けました。
私は2つの問題にぶつかりましたが、他の人も知っておくべきです:
承認された回答にあるような制約を追加すると、赤い自動レイアウトエラーNeed constraints for: X position or width
が表示されます。これは、スタックビューのサブビューとしてUILabelを追加することで解決されました。
サブビューをプログラムで追加しているので、ストーリーボードにはサブビューがありませんでした。自動レイアウトエラーを解消するには、ストーリーボードにサブビューを追加してから、実際のサブビューと制約を追加する前にロード時にそれを削除します。
私はもともとUIStackViewにUIButtons
を追加しようとしました。ボタンとビューはロードされますが、スクロールビューはスクロールされません。これは、ボタンの代わりにUILabels
をスタックビューに追加することで解決されました。同じ制約を使用して、UILabelを持つこのビュー階層はスクロールしますが、UIButtonはスクロールしません。
UIButtonsdoがIntrinsicContentSize(スタックビューで使用)を持っているように見えるので、私はこの問題に混乱しています。ボタンが機能しない理由を誰かが知っている場合は、その理由を知りたいと思います。
参考までに、これが私のビューの階層と制約です。
私は同じことをやろうと思っていて、これにつまずいていました 優れた投稿 もしあなたがプログラム的にアンカーAPIを使ってこれをしたいのなら、これが道です。
まとめると、UIStackView
をUIScrollView
に埋め込み、UIStackView
のアンカー制約をUIScrollView
のアンカー制約と一致するように設定します。
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
空白のフルスクリーンシーンがある
スクロールビューを追加します。 Ctrlキーを押しながらスクロールビューからドラッグベースビューへ、左から右、上から下、すべてゼロを追加します。
スクロールビューにスタックビューを追加します。スタックビューからControlキーを押しながらドラッグスクロールビューへ、左から右、上から下、すべてゼロを追加します。
スタックビュー内に1つのUILabelを配置します。
明確にするために、背景色を赤にします。高さを100に設定し、スタックビューで間隔を20に設定します。
次に、UILabelの幅を設定します。
驚いたことに、UILabel
からスクロールビューにnotをドラッグし、等しい幅を選択します。
繰り返す:
とても簡単です。それが秘密です。
できました。とても簡単です。
ヒント:スタックビューに新しいアイテム、たとえばUIView(おそらくスペースとして使用される)を追加してみてください。すべてがうまくいかないことに注意してください。実際には、すべての新しいアイテムに高さを追加する必要があります(たとえば、「100」)。新しいアイテムを追加するたびに、何らかの方法で高さを指定する必要があります。
別の見方:
上記では、これを言っています:驚くべきことに、UILabelsの幅をスクロールビュー(スタックビューではない)の幅に設定します。それは完全に機能します。
代わりに...
スタックビューは、親であるスクロールビューに左右に固定されていることに注意してください。これを試して:
したがって、2つのオプションがあります。
または
明確にするために、これらの方法のいずれかを実行し、両方を実行しないでください。
これをviewdidload
に追加するだけです。
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
水平スクロール用です。まず、UIStackView
とUIScrollView
を作成し、次の方法でそれらをビューに追加します。
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
translatesAutoresizingMaskIntoConstraints
とfalse
でUIStackView
をUIScrollView
に設定することを忘れないでください。
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
UIStackView
の末尾、先頭、上下のアンカーをすべてうまく機能させるには、UIScrollView
アンカーと等しくなければなりません。
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
しかしUIStackView
の幅アンカーは、UIScrollView
アンカーの幅以上でなければなりません。
stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true
それでは、あなたのUIScrollView
を固定しましょう。
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo:view.trailingAnchor).isActive = true
次に、UIStackView
の配置と配置について次の設定を試すことをお勧めします。
topicStackView.axis = .horizontal
topicStackView.distribution = .equalCentering
topicStackView.alignment = .center
topicStackView.spacing = 10
最後に、UIStackViewにサブビューを追加するためにaddArrangedSubview:
メソッドを使用する必要があります。
UIStackView
はUIScrollView
内に保持されているため、テキストのインセットにアクセスして、見栄えを少しよくすることができます。
let inset:CGFloat = 20
scrollView.contentInset.left = inset
scrollView.contentInset.right = inset
// remember if you're using insets then reduce the width of your stack view to match
stackView.widthAnchor.constraint(greaterThanOrEqualTo: topicScrollView.widthAnchor, constant: -inset*2).isActive = true
あなたは試すことができますScrollableStackView: https://github.com/gurhub/ScrollableStackView
Objective-CとSwiftの互換ライブラリです。それは CocoaPods を通して利用可能です。
サンプルコード(Swift)
import ScrollableStackView
var scrollable = ScrollableStackView(frame: view.frame)
view.addSubview(scrollable)
// add your views with
let rectangle = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 55))
rectangle.backgroundColor = UIColor.blue
scrollable.stackView.addArrangedSubview(rectangle)
// ...
サンプルコード(Objective-C)
@import ScrollableStackView
ScrollableStackView *scrollable = [[ScrollableStackView alloc] initWithFrame:self.view.frame];
scrollable.stackView.distribution = UIStackViewDistributionFillProportionally;
scrollable.stackView.alignment = UIStackViewAlignmentCenter;
scrollable.stackView.axis = UILayoutConstraintAxisVertical;
[self.view addSubview:scrollable];
UIView *rectangle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 55)];
[rectangle setBackgroundColor:[UIColor blueColor]];
// add your views with
[scrollable.stackView addArrangedSubview:rectangle];
// ...
スクロールビュー内でスタックビューを垂直方向の中央に配置するという制約がある場合は、削除してください。
スクロールビューをシーンに配置し、シーン全体に収まるようにサイズを変更します。次に、スクロールビュー内にスタックビューを配置し、スタックビュー内に項目の追加ボタンを配置します。すべてが整ったら、次の制約を設定します。
Scroll View.Leading = Superview.LeadingMargin
Scroll View.Trailing = Superview.TrailingMargin
Scroll View.Top = Superview.TopMargin
Bottom Layout Guide.Top = Scroll View.Bottom + 20.0
Stack View.Leading = Scroll View.Leading
Stack View.Trailing = Scroll View.Trailing
Stack View.Top = Scroll View.Top
Stack View.Bottom = Scroll View.Bottom
Stack View.Width = Scroll View.Width
code:Stack View.Width = Scroll View.Width
がキーです。
垂直方向のスタックビュー/スクロールビューの例(自動レイアウトにEasyPeasy
を使用):
let scrollView = UIScrollView()
self.view.addSubview(scrollView)
scrollView <- [
Edges(),
Width().like(self.view)
]
let stackView = UIStackView(arrangedSubviews: yourSubviews)
stackView.axis = .vertical
stackView.distribution = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView <- [
Edges(),
Width().like(self.view)
]
サブビューの高さがそれぞれ定義されていることを確認してください。
何よりもまずSketchのようなものでビューをデザインするか、スクロール可能なコンテンツとして何をしたいのかを考えてください。
その後、View Controllerを自由形式にし(属性インスペクタから選択)、ビューの本来のコンテンツサイズ(高さインスペクタから選択)に従って高さと幅を設定します。
この後、View Controllerでスクロールビューを配置しました。これはロジックです。IOSでほぼ常に動作していることがわかりました(コマンド+クリックで取得できるビュークラスのドキュメントを読む必要があるかもしれません)。そのクラスまたはグーグル経由で)
あなたが2つ以上のビューで作業しているなら、最初に先に導入されたまたはより原始的なビューから始めて、そして後で導入されたまたはより近代的なビューに行ってください。最初に導入されたのは、最初にスクロールビューから始めて、次にスタックビューに移動しますここで、そのスーパービューに対して全方向にスクロールビューの制約を0に設定します。スタックビューで
スタックビューで作業中
つまり、ビューにラベル、テキストフィールド、および画像がある場合は、まずこれらのビューを(スクロールビュー内に)配置し、その後、それらをスタックビューに配置します。
その後、スタックビューのプロパティを微調整します。それでも目的のビューが得られない場合は、別のスタックビューを使用してください。
ビューを作成したら、マザースタックビューとスクロールビューの間に制約を設定し、子スタックビューにはマザースタックビューを使用します。うまくいけば、この時点でそれはうまくいくはずです、あるいはあなたはXcodeから提案を与える警告を受け、それが言うことを読みそしてそれらを実行するかもしれません。うまくいけば今、あなたはあなたの期待通りに作業の視野を持つべきです:)。
横スクロールビューをお探しの方
func createHorizontalStackViewsWithScroll() {
self.view.addSubview(stackScrollView)
stackScrollView.translatesAutoresizingMaskIntoConstraints = false
stackScrollView.heightAnchor.constraint(equalToConstant: 85).isActive = true
stackScrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackScrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackScrollView.bottomAnchor.constraint(equalTo: visualEffectViews.topAnchor).isActive = true
stackScrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: stackScrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: stackScrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: stackScrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: stackScrollView.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: stackScrollView.heightAnchor).isActive = true
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.axis = .horizontal
stackView.alignment = .fill
for i in 0 ..< images.count {
let photoView = UIButton.init(frame: CGRect(x: 0, y: 0, width: 85, height: 85))
// set button image
photoView.translatesAutoresizingMaskIntoConstraints = false
photoView.heightAnchor.constraint(equalToConstant: photoView.frame.height).isActive = true
photoView.widthAnchor.constraint(equalToConstant: photoView.frame.width).isActive = true
stackView.addArrangedSubview(photoView)
}
stackView.setNeedsLayout()
}