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
Is it possible for UIStackView to scroll?
提问by itsaboutcode
Let's say I have added more views in UIStackView which can be displayed, how I can make the UIStackView
scroll?
假设我在 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):
基本上,要重新创建示例(用于垂直滚动):
- Create a
UIScrollView
, and set its constraints. - Add a
UIStackView
to theUIScrollView
- Set the constraints:
Leading
,Trailing
,Top
&Bottom
should be equal to the ones fromUIScrollView
- Set up an equal
Width
constraint between theUIStackView
andUIScrollView
. - Set Axis = Vertical, Alignment = Fill, Distribution = Equal Spacing, and Spacing = 0 on the
UIStackView
- Add a number of
UIViews
to theUIStackView
- Run
- 创建一个
UIScrollView
,并设置其约束。 - 一个添加
UIStackView
到UIScrollView
- 设置约束:
Leading
,Trailing
,Top
&Bottom
应该等于来自UIScrollView
Width
在UIStackView
和之间设置一个相等的约束UIScrollView
。- 设置 Axis = Vertical、Alignment = Fill、Distribution = Equal Spacing 和 Spacing = 0
UIStackView
- 添加一些
UIViews
到UIStackView
- 跑
Exchange Width
for Height
in step 4, and set Axis
= Horizontal
in step 5, to get a horizontal UIStackView.
在第 4 步中交换Width
for 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 包括关于使用滚动视图的整个部分。一些相关的片段:
- 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.
- (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.
- (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.
- 将内容视图的顶部、底部、前缘和后缘固定到滚动视图的相应边缘。内容视图现在定义滚动视图的内容区域。
- (可选)要禁用水平滚动,请将内容视图的宽度设置为等于滚动视图的宽度。内容视图现在水平填充滚动视图。
- (可选)要禁用垂直滚动,请将内容视图的高度设置为等于滚动视图的高度。内容视图现在水平填充滚动视图。
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, UIStackView
and UIScrollView
play together nicely, see here.
作为EIK说,UIStackView
并UIScrollView
很好地一起玩,看这里。
The key is that the UIStackView
handles the variable height/width for different contents and the UIScrollView
then 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:
我确实遇到了两个问题,但其他人应该注意:
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.
I originally attempted to add
UIButtons
to the UIStackView. The buttons and views would load, but the scroll view would not scroll. This was solved by addingUILabels
to 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.
添加类似于已接受答案中的约束后,我会收到红色 autolayout error
Need constraints for: X position or width
。这是通过添加 UILabel 作为堆栈视图的子视图来解决的。我以编程方式添加子视图,所以我最初在情节提要上没有子视图。要摆脱自动布局错误,请向情节提要中添加一个子视图,然后在添加真正的子视图和约束之前在加载时将其删除。
我最初试图添加
UIButtons
到 UIStackView。按钮和视图会加载,但滚动视图不会滚动。这是通过添加UILabels
到堆栈视图而不是按钮来解决的。使用相同的约束,这个带有 UILabels 的视图层次结构会滚动,但 UIButtons 不会。我被这个问题困惑,因为UIButtons都似乎有一个IntrinsicContentSize(由堆栈视图中使用)。如果有人知道为什么按钮不起作用,我很想知道为什么。
Here is my view hierarchy and constraints, for reference:
这是我的视图层次结构和约束,供参考:
回答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 UIStackView
in your UIScrollView
, and set the anchor constraints of the UIStackView
to match those of the UIScrollView
:
总而言之,将您的 嵌入您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
回答by Fattie
Up to date for 2020.
到 2020 年为止。
100% storyboard OR 100% code.
100% 故事板或 100% 代码。
Here's the simplest possible explanation:
这是最简单的解释:
Have a blank full-screen scene
Add a scroll view. Control-drag from the scroll view to the base view, add left-right-top-bottom, all zero.
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.
Put two or three labels inside the stack view.
有一个空白的全屏场景
添加滚动视图。Control-drag 从滚动视图到基本视图,添加左-右-上-下,全部为零。
在滚动视图中添加堆栈视图。Control-drag 从 stack view到 scroll view,添加 left-right-top-bottom ,全部为零。
在堆栈视图中放置两个或三个标签。
For clarity, make the background color of the label red. Set the label height to 100.
为清楚起见,将标签的背景颜色设为红色。将标签高度设置为 100。
Now set the widthof each UILabel:
Surprisingly, control-drag from the
UILabel
to the scroll view, notto the stack view, and select equal widths.
现在设置每个 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:
所以你有两个选择:
- Surprisingly, set the width of each item in the stack view to the width of the scrollview grandparent (not the stackview parent).
- 令人惊讶的是,将堆栈视图中每个项目的宽度设置为滚动视图祖父级(而不是堆栈视图父级)的宽度。
or
或者
- 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.
- 令人惊讶的是,将堆栈视图的“宽度等于”设置为滚动视图 -即使您确实将堆栈视图的左右边缘固定在滚动视图上。
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
来源: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 UIStackView
and a UIScrollView
and 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 translatesAutoresizingMaskIntoConstraints
to false
on the UIStackView
and the UIScrollView
:
记住设置translatesAutoresizingMaskIntoConstraints
,以false
在UIStackView
和UIScrollView
:
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
To get everything working the trailing, leading, top and bottom anchors of the UIStackView
should be equal to the UIScrollView
anchors:
为了让一切正常工作,尾随、前导、顶部和底部的锚点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 UIStackView
must the equal to or greater than the width of the UIScrollView
anchor:
但是锚的宽度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 UIStackView
alignment 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 UIStackView
is held within a UIScrollView
you 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
您可以尝试ScrollableStackView:https: //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
First and foremost design your view, preferably in something like Sketch or get an idea of what do you want as a scrollable content.
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).
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.
首先也是最重要的设计你的视图,最好是像 Sketch 这样的东西,或者了解你想要什么作为可滚动内容。
在此之后使视图控制器自由形式(从属性检查器中选择)并根据视图的内在内容大小(从大小检查器中选择)设置高度和宽度。
在此之后,在视图控制器中放置一个滚动视图,这是一个逻辑,我发现它几乎一直在 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 收到警告并提供建议,阅读它所说的内容并实施这些建议。希望现在您应该有一个符合您期望的工作视图:)。