表示できるビューをUIStackViewに追加したとしましょうUIStackView
。スクロールするにはどうすればよいですか?
表示できるビューをUIStackViewに追加したとしましょうUIStackView
。スクロールするにはどうすればよいですか?
回答:
コードなしのソリューションを探している人のために、自動レイアウトを使用して、ストーリーボードでこれを完全に行う例を作成しました。
githubから入手できます。
基本的に、例を再作成するには(垂直スクロールの場合):
UIScrollView
、その制約を設定します。UIStackView
しますUIScrollView
Leading
、Trailing
、Top
&Bottom
からのものと同じでなければなりませんUIScrollView
Width
の間の制約UIStackView
とをUIScrollView
。UIStackView
UIViews
しますUIStackView
手順4でを交換Width
しHeight
、手順5でAxis
= を設定Horizontal
して、水平方向のUIStackViewを取得します。
Appleの自動レイアウトガイドには、スクロールビューの操作に関するセクション全体が含まれています。関連するスニペット:
- コンテンツビューの上部、下部、リーディング、トレーリングエッジをスクロールビューの対応するエッジに固定します。コンテンツビューは、スクロールビューのコンテンツ領域を定義するようになりました。
- (オプション)水平スクロールを無効にするには、コンテンツビューの幅をスクロールビューの幅に設定します。コンテンツビューがスクロールビューを水平方向に塗りつぶします。
- (オプション)垂直スクロールを無効にするには、コンテンツビューの高さをスクロールビューの高さと等しく設定します。コンテンツビューがスクロールビューを水平方向に塗りつぶします。
さらに:
レイアウトでは、コンテンツビューのサイズを完全に定義する必要があります(手順5および6で定義されている場合を除く)。…コンテンツビューがスクロールビューよりも高い場合、スクロールビューは垂直スクロールを可能にします。コンテンツビューがスクロールビューよりも広い場合、スクロールビューは水平スクロールを可能にします。
要約すると、(この場合、スタックビュー)スクロールビューのコンテンツビューは、その端部に固定されなければならないし、その幅及び/又は高さは、さもなければ拘束しています。つまり、スタックビューのコンテンツは、スクロールが必要な方向に(直接的または間接的に)制約される必要があります。これは、たとえば、垂直にスクロールするスタックビュー内の各ビューに高さ制約を追加することを意味します。以下は、スタックビューを含むスクロールビューの垂直スクロールを可能にする方法の例です。
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
Need constraints for: Y position or height.
このエラーが発生します。このエラーは、垂直スクロールを無効にするスタックビューの幅と高さの両方の制約を設定した場合にのみ解消されます。このコードはまだ機能しますか?
ここで上位投票された回答の制約がうまくいきました。ストーリーボードで作成したように、以下の制約の画像を貼り付けました。
私は2つの問題にぶつかりましたが、他の人は注意する必要があります:
承認された回答と同様の制約を追加すると、赤いautolayoutエラーが発生しますNeed constraints for: X position or width
。これは、UILabelをスタックビューのサブビューとして追加することで解決しました。
プログラムでサブビューを追加しているので、ストーリーボードには最初はサブビューがありませんでした。自動レイアウトエラーを取り除くには、サブビューをストーリーボードに追加し、実際のサブビューと制約を追加する前にロード時に削除します。
私は最初にUIButtons
UIStackView に追加しようとしました。ボタンとビューは読み込まれますが、スクロールビューはスクロールしません。これはUILabels
、ボタンの代わりにスタックビューに追加することで解決しました。同じ制約を使用して、UILabelsを持つこのビュー階層はスクロールしますが、UIButtonsはスクロールしません。
UIButton が(スタックビューで使用される)IntrinsicContentSizeを持っているように見えるので、私はこの問題で混乱しています。ボタンが機能しない理由を誰かが知っているなら、私はその理由を知りたいです。
参考のために、ここに私のビュー階層と制約を示します。
Eikが言うように、UIStackView
そしてUIScrollView
一緒に上手に遊ぶには、ここを参照してください。
重要なのは、UIStackView
がさまざまなコンテンツの可変の高さ/幅を処理し、UIScrollView
そのコンテンツをそのコンテンツのスクロール/バウンスにうまく機能させることです。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
私は同じことをしようとしていて、この素晴らしい投稿に出会いました。アンカー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キーを押しながらドラッグし、left-right-top-bottomをすべてゼロに追加します。
スクロールビューにスタックビューを追加します。スタックビューからスクロールビューにCtrlキーを押しながらドラッグし、左上、右下、すべてゼロを追加します。
スタックビュー内に2つまたは3つのラベルを配置します。
わかりやすくするために、ラベルの背景色を赤にします。ラベルの高さを100に設定します。
次に、各UILabel の幅を設定します。
驚いたことに、スタックビューではなくUILabel
、スクロールビューからCtrlキーを押しながらドラッグして、同じ幅を選択します。
繰り返す:
とても簡単です。それが秘密です。
秘密のヒント-Appleバグ:
それは動作しません一つだけのアイテムに!いくつかのラベルを追加して、デモを機能させます。
完了です。
ヒント:すべての新しいアイテムに高さを追加する必要があります。スクロールスタックビューのすべてのアイテムは、固有のサイズ(ラベルなど)を持っているか、明示的な高さ制約を追加する必要があります。
代替アプローチ:
上記の例では、驚くべきことに、UILabelsの幅を(スタックビューではなく)スクロールビューの幅に設定します。
あるいは...
したがって、2つのオプションがあります。
または
明確にするために、これらの方法のいずれかを実行し、両方を実行しないでください。
水平スクロール用。まず、a UIStackView
とa 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
最後に、このaddArrangedSubview:
メソッドを使用して、UIStackViewにサブビューを追加する必要があります。
便利だと思われる追加機能の1つは、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
これを追加するだけ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
あなたは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];
// ...
スタックビューをスクロールビューの垂直方向の中央に配置するという制約がある場合は、それを削除するだけです。
垂直スタックビュー/スクロールビューの例(EasyPeasy
for autolayout を使用):
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のようなものを使用するか、スクロール可能なコンテンツとして何が必要かを理解してください。
この後、ビューコントローラーをフリーフォームにし(属性インスペクターから選択)、ビューの固有のコンテンツサイズに従って高さと幅を設定します(サイズインスペクターから選択します)。
この後、ビューコントローラーにスクロールビューを配置します。これはロジックです。これは、iOSでほぼ常に機能していることがわかりました(コマンド+クリックで取得できるビュークラスのドキュメントを確認する必要がある場合があります)そのクラスまたはグーグル経由)
2つ以上のビューで作業している場合は、最初に、以前に導入された、またはより原始的なビューから始め、次に、後で導入された、またはより新しいビューに移動します。したがって、ここでは最初にスクロールビューが導入されているため、最初にスクロールビューから開始して、次にスタックビューに移動します。ここで、スクロールビューの制約を、そのスーパービューに対してすべての方向でゼロにします。すべてのビューをこのスクロールビュー内に配置してから、スタックビューに配置します。
スタックビューでの作業中
最初にグラウンドボトムアップ(ボトムアップアプローチ)から始めます。つまり、ビューにラベル、テキストフィールド、および画像がある場合は、これらのビューを最初に(スクロールビュー内に)レイアウトし、その後それらをスタックビューに配置します。
その後、スタックビューのプロパティを調整します。それでも目的のビューが得られない場合は、別のスタックビューを使用してください。
ビューを作成した後、マザースタックビューとスクロールビューの間に制約を設定し、子スタックビューはマザースタックビューとスタックします。うまくいけば、この時間までにそれがうまく機能するか、提案を与えるXcodeから警告を受け取り、それが言うことを読んでそれらを実装するかもしれません。うまくいけば、今あなたはあなたの期待どおりに実際の見解を持っているはずです:)。
ネストされたまたは単一のスタックビューの場合、スクロールビューはルートビューで固定幅を設定する必要があります。スクロールビュー内にあるメインスタックビューは、同じ幅を設定する必要があります。[私のスクロールビューはビューの下にあり、無視してください]
UIStackViewとUIScrollViewの間に同じ幅の制約を設定します。
水平スクロールビューを探している人がいる場合
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()
}
シーンにスクロールビューを配置し、シーン全体に収まるようにサイズを変更します。次に、スタックビューをスクロールビュー内に配置し、アイテムの追加ボタンをスタックビュー内に配置します。すべての準備が整ったら、次の制約を設定します。
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
コード:Stack View.Width = Scroll View.Width
キーです。
macOS Catalystに新しい視点を追加します。macOSアプリはウィンドウのサイズ変更をサポートUIStackView
しているため、スクロールできない状態からスクロール可能な状態に、またはその逆に遷移する可能性があります。ここには微妙なことが2つあります。
UIStackView
それができるすべての領域に合うように設計されています。UIScrollView
ナビゲーションバー(またはmacOSアプリの場合はツールバー)の下の新しく取得または失われた領域を考慮して、境界のサイズを変更しようとします。これにより、残念ながら無限ループが発生します。私は非常に精通していないですUIScrollView
し、そのadjustedContentInset
が、その中に私のログからlayoutSubviews
の方法、私は、次の行動を見ています:
UIScrollView
境界を縮小しようとします(ツールバーの下の領域は必要ないため)。UIStackView
続く。UIScrollView
不満があり、より大きな境界に復元することにしました。丸太から私が見ているのはそのことなので、これは私には非常に奇妙に感じますUIScrollView.bounds.height == UIStackView.bounds.height
。UIStackView
続く。次の2つの手順で問題が解決するようです。
UIStackView.top
へUIScrollView.topMargin
。contentInsetAdjustmentBehavior
し.never
ます。ここでは、垂直方向に拡大する垂直スクロール可能なビューに関心がありUIStackView
ます。水平ペアの場合は、それに応じてコードを変更します。
それが将来誰にでも役立つことを願っています。インターネットでこれについて言及している人を見つけることができず、何が起こったのかを理解するのにかなりの時間がかかりました。