web-dev-qa-db-ja.com

UIStackViewはスクロールできますか?

UIStackViewに表示可能なビューを追加したとしましょう。どうすればUIStackViewスクロールを作成できますか?

160
itsaboutcode

誰かが解決策を探しているのであればコードなし、私は自動レイアウトを使用して、ストーリーボードでこれを完全に行うための例を作成しました。

github から入手できます。

基本的に、例を再現するには:

  1. UIScrollViewを作成し、その制約を設定します。
  2. UIStackViewUIScrollViewに追加します
  3. LeadingTrailingTop、およびBottomUIScrollViewからのものと等しくなければなりません。
  4. WidthUIStackViewの間に等しいUIScrollView制約を設定します。
  5. UIStackViewで、Axis = Vertical、Alignment = Fill、Distribution = Equal Spacing、およびSpacing = 0を設定します。
  6. UIViewsに多数のUIStackViewを追加します。
  7. 実行する
466
Arjan

AppleのAuto Layout Guideには、 Scroll Viewsの操作 に関する全セクションがあります。いくつかの関連スニペット:

  1. コンテンツビューの上下左右の端をスクロールビューの対応する端に固定します。コンテンツビューは、スクロールビューのコンテンツ領域を定義します。
  2. (オプション)水平スクロールを無効にするには、コンテンツビューの幅をスクロールビューの幅と同じに設定します。コンテンツビューはスクロールビューを水平方向に塗りつぶします。
  3. (オプション)垂直スクロールを無効にするには、コンテンツビューの高さをスクロールビューの高さと同じに設定します。コンテンツビューはスクロールビューを水平方向に塗りつぶします。

さらに:

レイアウトは、コンテンツビューのサイズを完全に定義する必要があります(手順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
37
titaniumdecoy

Eikが言うように、UIStackViewとUIScrollViewはうまく連携しています。 here を参照してください。

重要なのは、UIStackViewがさまざまなコンテンツに対して可変のheight/widthを処理し、UIScrollViewがそのコンテンツのスクロール/バウンスをうまく処理することです。

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)       
}
13
user1307434

ここで一番投票された答えの制約は私のために働きました、そして私は私のストーリーボードで作成されたように、下記の制約のイメージを貼り付けました。

私は2つの問題にぶつかりましたが、他の人も知っておくべきです:

  1. 承認された回答にあるような制約を追加すると、赤い自動レイアウトエラーNeed constraints for: X position or widthが表示されます。これは、スタックビューのサブビューとしてUILabelを追加することで解決されました。

    サブビューをプログラムで追加しているので、ストーリーボードにはサブビューがありませんでした。自動レイアウトエラーを解消するには、ストーリーボードにサブビューを追加してから、実際のサブビューと制約を追加する前にロード時にそれを削除します。

  2. 私はもともとUIStackViewにUIButtonsを追加しようとしました。ボタンとビューはロードされますが、スクロールビューはスクロールされません。これは、ボタンの代わりにUILabelsをスタックビューに追加することで解決されました。同じ制約を使用して、UILabelを持つこのビュー階層はスクロールしますが、UIButtonはスクロールしません。

    UIButtonsdoがIntrinsicContentSize(スタックビューで使用)を持っているように見えるので、私はこの問題に混乱しています。ボタンが機能しない理由を誰かが知っている場合は、その理由を知りたいと思います。

参考までに、これが私のビューの階層と制約です。

constraints for stack view in scroll view[1]

12
pkamb

私は同じことをやろうと思っていて、これにつまずいていました 優れた投稿 もしあなたがプログラム的にアンカーAPIを使ってこれをしたいのなら、これが道です。

まとめると、UIStackViewUIScrollViewに埋め込み、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
9
Dalmazio

2019年の最新情報。

100%ストーリーボードOR 100%コード。


最も簡単な説明を次に示します。

  1. 空白のフルスクリーンシーンがある

  2. スクロールビューを追加します。 Ctrlキーを押しながらスクロールビューからドラッグベースビューへ、左から右、上から下、すべてゼロを追加します。

  3. スクロールビューにスタックビューを追加します。スタックビューからControlキーを押しながらドラッグスクロールビューへ、左から右、上から下、すべてゼロを追加します。

  4. スタックビュー内に1つのUILabelを配置します。

明確にするために、背景色を赤にします。高さを100に設定し、スタックビューで間隔を20に設定します。

  1. 次に、UILabelの幅を設定します。

    驚いたことに、UILabelからスクロールビューにnotをドラッグし、等しい幅を選択します。

繰り返す:

UILabelからUILabelの親へのドラッグを制御しないでください-祖父母に移動してください。 (つまり、スクロールビューに移動し、スタックビューに移動しないでください。)

とても簡単です。それが秘密です。

  1. 次に、must UILabelをクリックします--must文字通りコピー&ペーストを数回押します。 It 機能しません 1つのアイテムのみ。 (「複製」をクリックしないで、「コピーして貼り付け」をクリックします。)

できました。とても簡単です。

ヒント:スタックビューに新しいアイテム、たとえばUIView(おそらくスペースとして使用される)を追加してみてください。すべてがうまくいかないことに注意してください。実際には、すべての新しいアイテムに高さを追加する必要があります(たとえば、「100」)。新しいアイテムを追加するたびに、何らかの方法で高さを指定する必要があります


別の見方:

上記では、これを言っています:驚くべきことに、UILabelsの幅をスクロールビュー(スタックビューではない)の幅に設定します。それは完全に機能します。

代わりに...

スタックビューは、親であるスクロールビューに左右に固定されていることに注意してください。これを試して:

スタックビューからスクロールビューにドラッグし、「幅が等しい」制約を追加します。これは奇妙なようですすでに左右を固定していますが、それがあなたのやり方です。どんなに奇妙であっても、それが秘密だと思われます。

したがって、2つのオプションがあります。

  1. 驚いたことに、UILabelsの幅をスクロールビューの祖父母の幅に設定します(stackview parentではありません)。

または

  1. 驚くべきことに、スタックビューの「等しい幅」をスクロールビューに設定します-にもかかわらず、あなたは左端と右端を持っていますとにかくスクロールビューに固定されたスタックビューの。

明確にするために、これらの方法のいずれかを実行し、両方を実行しないでください。

5
Fattie

これをviewdidloadに追加するだけです。

let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets

ソース: https://developer.Apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

5
rashad.z

水平スクロール(UIScrollView内のUIStackView)

水平スクロール用です。まず、UIStackViewUIScrollViewを作成し、次の方法でそれらをビューに追加します。

let scrollView = UIScrollView()
let stackView = UIStackView()

scrollView.addSubview(stackView)
view.addSubview(scrollView)

translatesAutoresizingMaskIntoConstraintsfalseUIStackViewUIScrollViewに設定することを忘れないでください。

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:メソッドを使用する必要があります。

テキストインセット

UIStackViewUIScrollView内に保持されているため、テキストのインセットにアクセスして、見栄えを少しよくすることができます。

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
4
sketchyTech

あなたは試すことができますScrollableStackViewhttps://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]; 
// ...
2
mgyky

ネストまたはシングルスタックビューの場合、スクロールビューはルートビューで固定幅に設定する必要があります。スクロールビューの内側にあるメインスタックビューは、同じ幅を設定する必要があります。 [私のスクロールビューはビューを無視して無視します]

UIStackViewとUIScrollViewの間に等しい幅の制約を設定します。

enter image description here

0

スクロールビュー内でスタックビューを垂直方向の中央に配置するという制約がある場合は、削除してください。

0
Ahmed Elashker

スクロールビューをシーンに配置し、シーン全体に収まるようにサイズを変更します。次に、スクロールビュー内にスタックビューを配置し、スタックビュー内に項目の追加ボタンを配置します。すべてが整ったら、次の制約を設定します。

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

enter image description here

code:Stack View.Width = Scroll View.Widthがキーです。

0
Joshua Cleetus

垂直方向のスタックビュー/スクロールビューの例(自動レイアウトに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)
]

サブビューの高さがそれぞれ定義されていることを確認してください。

0
dOM
  1. 何よりもまずSketchのようなものでビューをデザインするか、スクロール可能なコンテンツとして何をしたいのかを考えてください。

  2. その後、View Controllerを自由形式にし(属性インスペクタから選択)、ビューの本来のコンテンツサイズ(高さインスペクタから選択)に従って高さと幅を設定します。

  3. この後、View Controllerでスクロールビューを配置しました。これはロジックです。IOSでほぼ常に動作していることがわかりました(コマンド+クリックで取得できるビュークラスのドキュメントを読む必要があるかもしれません)。そのクラスまたはグーグル経由で)

    あなたが2つ以上のビューで作業しているなら、最初に先に導入されたまたはより原始的なビューから始めて、そして後で導入されたまたはより近代的なビューに行ってください。最初に導入されたのは、最初にスクロールビューから始めて、次にスタックビューに移動しますここで、そのスーパービューに対して全方向にスクロールビューの制約を0に設定します。スタックビューで

スタックビューで作業中

  • つまり、ビューにラベル、テキストフィールド、および画像がある場合は、まずこれらのビューを(スクロールビュー内に)配置し、その後、それらをスタックビューに配置します。

  • その後、スタックビューのプロパティを微調整します。それでも目的のビューが得られない場合は、別のスタックビューを使用してください。

  • それでも達成されない場合は、圧縮耐性またはコンテンツハグの優先順位で再生してください。
  • その後、スタックビューに制約を追加してください。
  • 上記のすべてで満足のいく結果が得られない場合は、空のUIViewをフィラービューとして使用することも検討してください。

ビューを作成したら、マザースタックビューとスクロールビューの間に制約を設定し、子スタックビューにはマザースタックビューを使用します。うまくいけば、この時点でそれはうまくいくはずです、あるいはあなたはXcodeから提案を与える警告を受け、それが言うことを読みそしてそれらを実行するかもしれません。うまくいけば今、あなたはあなたの期待通りに作業の視野を持つべきです:)。

0
Nikhil Pandey

横スクロールビューをお探しの方

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()

 }
0
user1039695