ios UIStackView 是否可以滚动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31668970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:01:41  来源:igfitidea点击:

Is it possible for UIStackView to scroll?

iosuiscrollviewuistackview

提问by itsaboutcode

Let's say I have added more views in UIStackView which can be displayed, how I can make the UIStackViewscroll?

假设我在 UIStackView 中添加了更多可以显示的视图,如何进行UIStackView滚动?

回答by Arjan

In case anyone is looking for a solution without code, I created an example to do this completely in the storyboard, using Auto Layout.

如果有人正在寻找没有代码的解决方案,我创建了一个示例来完全在情节提要中使用自动布局完成此操作。

You can get it from github.

你可以从github获取它。

Basically, to recreate the example (for vertical scrolling):

基本上,要重新创建示例(用于垂直滚动):

  1. Create a UIScrollView, and set its constraints.
  2. Add a UIStackViewto the UIScrollView
  3. Set the constraints: Leading, Trailing, Top& Bottomshould be equal to the ones from UIScrollView
  4. Set up an equal Widthconstraint between the UIStackViewand UIScrollView.
  5. Set Axis = Vertical, Alignment = Fill, Distribution = Equal Spacing, and Spacing = 0 on the UIStackView
  6. Add a number of UIViewsto the UIStackView
  7. Run
  1. 创建一个UIScrollView,并设置其约束。
  2. 一个添加UIStackViewUIScrollView
  3. 设置约束:Leading, Trailing, Top&Bottom应该等于来自UIScrollView
  4. WidthUIStackView和之间设置一个相等的约束UIScrollView
  5. 设置 Axis = Vertical、Alignment = Fill、Distribution = Equal Spacing 和 Spacing = 0 UIStackView
  6. 添加一些UIViewsUIStackView

Exchange Widthfor Heightin step 4, and set Axis= Horizontalin step 5, to get a horizontal UIStackView.

在第 4 步中交换Widthfor Height,并在第 5 步中设置Axis= Horizontal,以获得一个水平的 UIStackView。

回答by titaniumdecoy

Apple's Auto Layout Guide includes an entire section on Working with Scroll Views. Some relevant snippets:

Apple 的 Auto Layout Guide 包括关于使用滚动视图的整个部分。一些相关的片段:

  1. Pin the content view's top, bottom, leading, and trailing edges to the scroll view's corresponding edges. The content view now defines the scroll view's content area.
  2. (Optional) To disable horizontal scrolling, set the content view's width equal to the scroll view's width. The content view now fills the scroll view horizontally.
  3. (Optional) To disable vertical scrolling, set the content view's height equal to the scroll view's height. The content view now fills the scroll view horizontally.
  1. 将内容视图的顶部、底部、前缘和后缘固定到滚动视图的相应边缘。内容视图现在定义滚动视图的内容区域。
  2. (可选)要禁用水平滚动,请将内容视图的宽度设置为等于滚动视图的宽度。内容视图现在水平填充滚动视图。
  3. (可选)要禁用垂直滚动,请将内容视图的高度设置为等于滚动视图的高度。内容视图现在水平填充滚动视图。

Furthermore:

此外:

Your layout must fully define the size of the content view (except where defined in steps 5 and 6). … When the content view is taller than the scroll view, the scroll view enables vertical scrolling. When the content view is wider than the scroll view, the scroll view enables horizontal scrolling.

您的布局必须完全定义内容视图的大小(步骤 5 和 6 中定义的除外)。... 当内容视图比滚动视图高时,滚动视图启用垂直滚动。当内容视图比滚动视图宽时,滚动视图启用水平滚动。

To summarize, the scroll view's content view (in this case, a stack view) must be pinned to its edges andhave its width and/or height otherwise constrained. That means that the contents of the stack view must be constrained (directly or indirectly) in the direction(s) in which scrolling is desired, which might mean adding a height constraint to each view inside a vertically scrolling stack view, for example. The following is an example of how to allow for vertical scrolling of a scroll view containing a stack view:

总而言之,滚动视图的内容视图(在这种情况下,堆栈视图)必须固定在其边缘并对其宽度和/或高度进行限制。这意味着必须在需要滚动的方向上(直接或间接地)限制堆栈视图的内容,例如,这可能意味着向垂直滚动堆栈视图内的每个视图添加高度约束。以下是如何允许垂直滚动包含堆栈视图的滚动视图的示例:

// 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

回答by user1307434

As Eik says, UIStackViewand UIScrollViewplay together nicely, see here.

作为EIK说,UIStackViewUIScrollView很好地一起玩,看这里

The key is that the UIStackViewhandles the variable height/width for different contents and the UIScrollViewthen does its job well of scrolling/bouncing that content:

关键是UIStackView处理不同内容的可变高度/宽度,UIScrollView然后很好地滚动/弹跳该内容:

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

回答by pkamb

The constraints in the top-voted answer here worked for me, and I've pasted an image of the constraints below, as created in my storyboard.

此处最高投票答案中的约束对我有用,并且我在下面粘贴了在我的故事板中创建的约束图像。

I did hit two issues though that others should be aware of:

我确实遇到了两个问题,但其他人应该注意:

  1. After adding constraints similar to those in in the accepted answer, I'd get the red autolayout error Need constraints for: X position or width. This was solved by adding a UILabel as a subview of the stack view.

    I'm adding the subviews programmatically, so I originally had no subviews on the storyboard. To get rid of the autolayout errors, add a subview to the storyboard, then remove it on load before adding your real subviews and constraints.

  2. I originally attempted to add UIButtonsto the UIStackView. The buttons and views would load, but the scroll view would not scroll. This was solved by adding UILabelsto the Stack View instead of buttons. Using the same constraints, this view hierarchy with the UILabels scrolls but the UIButtons does not.

    I'm confused by this issue, as the UIButtons doseem to have an IntrinsicContentSize (used by the Stack View). If anyone knows why the buttons don't work, I'd love to know why.

  1. 添加类似于已接受答案中的约束后,我会收到红色 autolayout error Need constraints for: X position or width。这是通过添加 UILabel 作为堆栈视图的子视图来解决的。

    我以编程方式添加子视图,所以我最初在情节提要上没有子视图。要摆脱自动布局错误,请向情节提要中添加一个子视图,然后在添加真正的子视图和约束之前在加载时将其删除。

  2. 我最初试图添加UIButtons到 UIStackView。按钮和视图会加载,但滚动视图不会滚动。这是通过添加UILabels到堆栈视图而不是按钮来解决的。使用相同的约束,这个带有 UILabels 的视图层次结构会滚动,但 UIButtons 不会。

    我被这个问题困惑,因为UIButtons似乎有一个IntrinsicContentSize(由堆栈视图中使用)。如果有人知道为什么按钮不起作用,我很想知道为什么。

Here is my view hierarchy and constraints, for reference:

这是我的视图层次结构和约束,供参考:

constraints for stack view in scroll view[1]

滚动视图中堆栈视图的约束[1]

回答by Dalmazio

I was looking to do the same thing and stumbled upon this excellent post.If you want to do this programmatically using the anchor API, this is the way to go.

我想做同样的事情,偶然发现了这篇优秀的帖子。如果您想使用锚点 API 以编程方式执行此操作,这就是要走的路。

To summarize, embed your UIStackViewin your UIScrollView, and set the anchor constraints of the UIStackViewto match those of the UIScrollView:

总而言之,将您的 嵌入您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

回答by Fattie

Up to date for 2020.

到 2020 年为止。

100% storyboard OR 100% code.

100% 故事板或 100% 代码。



Here's the simplest possible explanation:

这是最简单的解释:

  1. Have a blank full-screen scene

  2. Add a scroll view. Control-drag from the scroll view to the base view, add left-right-top-bottom, all zero.

  3. Add a stack view in the scroll view. Control-drag from the stack view to the scroll view, add left-right-top-bottom, all zero.

  4. Put two or three labels inside the stack view.

  1. 有一个空白的全屏场景

  2. 添加滚动视图。Control-drag 从滚动视图到基本视图,添加左-右-上-下,全部为零。

  3. 在滚动视图中添加堆栈视图。Control-drag 从 stack view到 scroll view,添加 left-right-top-bottom ,全部为零。

  4. 在堆栈视图中放置两个或三个标签。

For clarity, make the background color of the label red. Set the label height to 100.

为清楚起见,将标签的背景颜色设为红色。将标签高度设置为 100。

  1. Now set the widthof each UILabel:

    Surprisingly, control-drag from the UILabelto the scroll view, notto the stack view, and select equal widths.

  1. 现在设置每个 UILabel的宽度

    令人惊讶的是,从 控制拖动UILabel到滚动视图,而不是堆栈视图,并选择等宽

To repeat:

重复:

Don't control drag from the UILabel to the UILabel's parent - go to the grandparent. (In other words, go all the way to the scroll view, do not go to the stack view.)

不要控制从 UILabel 拖动到 UILabel 的父级 - 转到祖父级。(换句话说,一直到滚动视图,不要去堆栈视图。)

It's that simple. That's the secret.

就这么简单。这就是秘密。

Secret tip - Apple bug:

It will not workwith only one item! Add a few labels to make the demo work.

秘密提示 - 苹果错误:

不适用于仅一项!添加一些标签以使演示工作。

You're done.

你完成了。

Tip: You must add a height to every new item. Every item in any scrolling stack view must have either an intrinsic size (such as a label) or add an explicit height constraint.

提示:您必须为每个新项目添加高度。任何滚动堆栈视图中的每个项目都必须具有固有大小(例如标签)或添加明确的高度约束。



The alternative approach:

替代方法:

In the above: surprisingly, set the widths of the UILabels to the width of the scroll view (not the stack view).

在上面:令人惊讶的是,将 UILabels 的宽度设置为滚动视图(而不是堆栈视图)的宽度。

Alternately...

交替...

Drag from the stack view to the scroll view, and add a "width equal" constraint. This seems strange because you already pinned left-right, but that is how you do it. No matter how strange it seems that's the secret.

从堆栈视图拖动到滚动视图,并添加“宽度相等”约束。这看起来很奇怪,因为您已经固定了 left-right,但这就是您的方式。不管看起来多么奇怪,这就是秘密。

So you have two options:

所以你有两个选择:

  1. Surprisingly, set the width of each item in the stack view to the width of the scrollview grandparent (not the stackview parent).
  1. 令人惊讶的是,将堆栈视图中每个项目的宽度设置为滚动视图祖父级(而不是堆栈视图父级)的宽度。

or

或者

  1. Surprisingly, set a "width equal" of the stackview to the scrollview - even thoughyou do have the left and right edges of the stackview pinned to the scrollview anyway.
  1. 令人惊讶的是,将堆栈视图的“宽度等于”设置为滚动视图 -即使您确实将堆栈视图的左右边缘固定在滚动视图上。

To be clear, do ONE of those methods, do NOT do both.

需要明确的是,执行其中一种方法,不要同时执行这两种方法。

回答by Rashad.Z

Just add this to viewdidload:

只需将此添加到viewdidload

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

source: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

来源:https: //developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

回答by sketchyTech

Horizontal Scrolling (UIStackView within UIScrollView)

水平滚动(UIScrollView 中的 UIStackView)

For horizontal scrolling. First, create a UIStackViewand a UIScrollViewand add them to your view in the following way:

用于水平滚动。首先,创建 aUIStackView和 aUIScrollView并按以下方式将它们添加到您的视图中:

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

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

Remembering to set the translatesAutoresizingMaskIntoConstraintsto falseon the UIStackViewand the UIScrollView:

记住设置translatesAutoresizingMaskIntoConstraints,以falseUIStackViewUIScrollView

stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false

To get everything working the trailing, leading, top and bottom anchors of the UIStackViewshould be equal to the UIScrollViewanchors:

为了让一切正常工作,尾随、前导、顶部和底部的锚点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

But the width anchor of the UIStackViewmust the equal to or greater than the width of the UIScrollViewanchor:

但是锚的宽度UIStackView必须等于或大于UIScrollView锚的宽度:

stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true

Now anchor your UIScrollView, for example:

现在锚定您的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 

Next, I would suggest trying the following settings for the UIStackViewalignment and distribution:

接下来,我建议尝试以下UIStackView对齐和分布设置:

topicStackView.axis = .horizontal
topicStackView.distribution = .equalCentering
topicStackView.alignment = .center

topicStackView.spacing = 10

Finally you'll need to use the addArrangedSubview:method to add subviews to your UIStackView.

最后,您需要使用该addArrangedSubview:方法将子视图添加到您的 UIStackView。

Text Insets

文本插入

One additional feature that you might find useful is that because the UIStackViewis held within a UIScrollViewyou now have access to text insets to make things look a bit prettier.

您可能会发现有用的另一个功能是,因为UIStackView保存在 a 中,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

回答by mgyky

You can try ScrollableStackView: https://github.com/gurhub/ScrollableStackView

您可以尝试ScrollableStackViewhttps: //github.com/gurhub/ScrollableStackView

It's Objective-C and Swift compatible library. It's available through CocoaPods.

它是 Objective-C 和 Swift 兼容的库。它可以通过CocoaPods 获得

Sample Code (Swift)

示例代码 (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)
// ...

Sample Code (Objective-C)

示例代码(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]; 
// ...

回答by Nikhil Pandey

  1. First and foremost design your view, preferably in something like Sketch or get an idea of what do you want as a scrollable content.

  2. After this make the view controller free form (choose from attribute inspector) and set height and width as per the intrinsic content size of your view (to be chosen from the size inspector).

  3. After this in the view controller put a scroll view and this is a logic, which I have found to be working almost all the times in iOS (it may require going through the documentation of that view class which one can obtain via command + click on that class or via googling)

    If you are working with two or more views then first start with a view, which has been introduced earlier or is more primitive and then go to the view which has been introduced later or is more modern. So here since scroll view has been introduced first, start with the scroll view first and then go to the stack view. Here put scroll view constraints to zero in all direction vis-a-vis its super view. Put all your views inside this scroll view and then put them in stack view.

  1. 首先也是最重要的设计你的视图,最好是像 Sketch 这样的东西,或者了解你想要什么作为可滚动内容。

  2. 在此之后使视图控制器自由形式(从属性检查器中选择)并根据视图的内在内容大小(从大小检查器中选择)设置高度和宽度。

  3. 在此之后,在视图控制器中放置一个滚动视图,这是一个逻辑,我发现它几乎一直在 iOS 中工作(它可能需要查看该视图类的文档,可以通过命令 + 单击该课程或通过谷歌搜索)

    如果您使用两个或更多视图,则首先从较早引入或更原始的视图开始,然后转到较晚引入或更现代的视图。所以这里既然先介绍了scroll view,那就先从scroll view开始,再到stack view。在这里,相对于其超级视图,将滚动视图约束在所有方向上都设置为零。将所有视图放在此滚动视图中,然后将它们放在堆栈视图中。

While working with stack view

使用堆栈视图时

  • First start with grounds up(bottoms up approach), ie., if you have labels, text fields and images in your view, then lay out these views first (inside the scroll view) and after that put them in the stack view.

  • After that tweak the property of stack view. If desired view is still not achieved, then use another stack view.

  • If still not achieved then play with compression resistance or content hugging priority.
  • After this add constraints to the stack view.
  • Also think of using an empty UIView as filler view, if all of the above is not giving satisfactory results.
  • 首先从基础开始(自下而上方法),即,如果您的视图中有标签、文本字段和图像,则首先布置这些视图(在滚动视图内),然后将它们放入堆栈视图中。

  • 之后调整堆栈视图的属性。如果仍然没有实现所需的视图,则使用另一个堆栈视图。

  • 如果仍然没有实现,则使用抗压性或内容拥抱优先级。
  • 在此之后向堆栈视图添加约束。
  • 还可以考虑使用空的 UIView 作为填充视图,如果以上所有方法都没有给出令人满意的结果。

After making your view, put a constraint between the mother stack view and the scroll view, while constraint children stack view with the mother stack view. Hopefully by this time it should work fine or you may get a warning from Xcode giving suggestions, read what it says and implement those. Hopefully now you should have a working view as per your expectations:).

创建视图后,在母堆栈视图和滚动视图之间放置约束,同时约束子堆栈视图与母堆栈视图。希望此时它应该可以正常工作,否则您可能会从 Xcode 收到警告并提供建议,阅读它所说的内容并实施这些建议。希望现在您应该有一个符合您期望的工作视图:)。