UIStackView 是否可以滚动?
Is it possible for UIStackView to scroll?
假设我在 UIStackView 中添加了更多可以显示的视图,我如何才能使 UIStackView
滚动?
正如 Eik 所说,UIStackView
和 UIScrollView
一起玩得很好,参见 here。
关键是 UIStackView
处理变量 height/width 不同的内容,然后 UIScrollView
很好地完成 scrolling/bouncing 内容的工作:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
只需将此添加到 viewdidload
:
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
如果有人正在寻找解决方案无需代码,我创建了一个示例来完全在故事板中使用自动布局来完成此操作。
您可以从 github.
获取
基本上,要重新创建示例(用于垂直滚动):
- 创建一个
UIScrollView
,并设置其约束。
- 在
UIScrollView
中添加一个 UIStackView
- 设置约束:
Leading
、Trailing
、Top
& Bottom
应该等于 UIScrollView
- 在
UIStackView
和UIScrollView
之间设置一个相等的Width
约束。
- 在
UIStackView
上设置轴 = 垂直、对齐 = 填充、分布 = 等间距和间距 = 0
- 在
UIStackView
中添加UIViews
个数
- 运行
将步骤4中的Width
换成Height
,并在步骤5中设置Axis
= Horizontal
,得到一个横向的UIStackView。
这里投票最高的答案中的限制条件对我有用,我在下面粘贴了限制条件的图像,这是在我的情节提要中创建的。
我确实遇到了两个问题,但其他人应该知道:
添加与已接受答案中的约束类似的约束后,我会收到红色自动布局错误 Need constraints for: X position or width
。这是通过添加 UILabel 作为堆栈视图的子视图解决的。
我正在以编程方式添加子视图,因此故事板上最初没有子视图。要消除自动布局错误,请将子视图添加到故事板,然后在加载时将其删除,然后再添加真正的子视图和约束。
我最初尝试将 UIButtons
添加到 UIStackView。按钮和视图会加载,但 滚动视图不会滚动 。这是通过将 UILabels
添加到堆栈视图而不是按钮来解决的。使用相同的约束,此视图层次结构与 UILabels 滚动,但 UIButtons 不滚动。
我对这个问题感到困惑,因为 UIButtons do 似乎有一个 IntrinsicContentSize(由 Stack View 使用)。如果有人知道为什么按钮不起作用,我很想知道为什么。
这是我的视图层次结构和约束,供参考:
Apple 的自动布局指南包括关于 Working with Scroll Views 的整个部分。一些相关的片段:
- 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.
此外:
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.
总而言之,滚动视图的内容视图(在本例中为堆栈视图)必须固定到其边缘 并且 的宽度 and/or 高度否则会受到限制.这意味着堆栈视图的内容必须(直接或间接地)在需要滚动的方向上受到约束,例如,这可能意味着向垂直滚动堆栈视图内的每个视图添加高度约束。以下是如何允许包含堆栈视图的滚动视图的垂直滚动的示例:
// 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
如果您有将堆栈视图在滚动视图内垂直居中的限制,只需将其删除。
2020 年最新信息。
100% 故事板或 100% 代码。
这个例子是垂直的:
这是最简单的解释:
有空白full-screen场景
添加滚动视图。 Control-drag从滚动视图到基本视图,添加left-right-top-bottom,全部为零。
在滚动视图中添加堆栈视图。 Control-drag从堆栈视图到滚动视图,添加left-right-top-bottom,全部为零。
在堆栈视图中放置两个或三个标签。
为清楚起见,将标签的背景色设为红色。将标签高度设置为 100.
现在设置每个 UILabel 的宽度:
令人惊讶的是,control-drag从UILabel
到滚动视图,不是到堆栈视图,select等宽.
重复:
不要控制从 UILabel 到 UILabel 的 parent 的拖动 - 转到 grandparent。 (换句话说,一路走到滚动视图,不要走到堆栈视图。)
就这么简单。这就是秘密。
Secret tip - Apple bug:
It will not work with only one item! Add a few labels to make the demo work.
大功告成。
提示:您必须为每个新项目添加高度。任何滚动堆栈视图中的每个项目都必须具有固有大小(例如标签)或添加显式高度限制。
替代方法:
回顾一下上面的方法:令人惊讶的是,将标签的宽度设置为滚动视图(而不是堆栈视图)的宽度。
这是另一种方法...
从堆栈视图拖动到滚动视图,并添加“宽度相等”约束。这看起来很奇怪,因为 您已经固定了 left-right,但是 您就是这样做的。不管看起来多么奇怪,这就是秘密。
所以你有两个选择:
- 令人惊讶的是,将stackview中每个项目的宽度设置为scrollview grandparent的宽度(不是stackviewparent).
或
- 令人惊讶的是,将堆栈视图的“宽度等于”设置为滚动视图 - 即使你确实有左右边缘无论如何固定到滚动视图的堆栈视图。
明确地说,只执行其中一种方法,不要同时执行两种方法。
你可以尝试 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];
// ...
首先也是最重要的是设计你的视图,最好是在 Sketch 之类的东西中,或者得到一个
关于您想要什么作为可滚动内容的想法。
之后使视图控制器自由形式(从属性中选择
inspector) 并根据内在内容设置高度和宽度
您的视图大小(从大小检查器中选择)。
之后在视图控制器中放置一个滚动视图,这是一个
逻辑,我发现它几乎一直在 iOS 中工作(它可能需要查看该视图的文档 class 可以通过命令获得该视图并单击 class或通过谷歌搜索)
如果您正在使用两个或多个视图,则首先从一个视图开始,该视图已被较早介绍或更原始,然后转到已被介绍的视图
后来或更现代。所以这里因为滚动视图已经
先介绍一下,先从scroll view开始,再到
堆栈视图。这里将滚动视图约束在所有方向 vis-a-vis 其超级视图中设置为零。将所有视图放入此滚动视图中,然后将它们放入堆栈视图中。
在使用堆栈视图时
首先从基础开始(自下而上的方法),即,如果您的视图中有标签、文本字段和图像,则首先布置这些视图(在滚动视图内)和之后将它们放在堆栈视图中。
之后调整堆栈视图的 属性。如果仍未实现所需视图,则使用另一个堆栈视图。
- 如果仍未达到,则使用压缩阻力或内容拥抱优先级进行播放。
- 在此之后向堆栈视图添加约束。
- 还可以考虑使用一个空的 UIView 作为填充视图,如果以上所有方法都没有给出令人满意的结果。
创建视图后,在母堆栈视图和滚动视图之间放置一个约束,同时约束子堆栈视图与母堆栈视图。
希望此时它应该可以正常工作,否则您可能会收到来自 Xcode 的警告并提供建议,阅读它所说的内容并实施这些建议。希望现在你应该有一个符合你期望的工作视图:)。
垂直示例 stackview/scrollview(使用 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)
]
只需确保定义了每个子视图的高度!
我正想做同样的事情并偶然发现了这个 excellent post. 如果您想使用锚点 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
对于嵌套或单个堆栈视图,滚动视图必须与根视图设置固定宽度。滚动视图内部的主堆栈视图必须设置相同的宽度。 [我的滚动视图在 View 下方忽略它]
Set up an equal Width constraint between the UIStackView and
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()
}
水平滚动(UIScrollView 中的 UIStackView)
用于水平滚动。首先,创建一个 UIStackView
和一个 UIScrollView
并按以下方式将它们添加到您的视图中:
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
记得在 UIStackView
和 UIScrollView
上将 translatesAutoresizingMaskIntoConstraints
设置为 false
:
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。
文本插入
您可能会发现一个有用的附加功能是,因为 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
在您的场景中放置一个滚动视图,并调整其大小使其充满场景。然后,在滚动视图中放置一个堆栈视图,并将添加项目按钮放置在堆栈视图中。一切就绪后,设置以下约束:
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 应用程序支持 window 调整大小,因此您的 UIStackView
可能会从不可滚动状态转换为可滚动状态,反之亦然。这里有两个微妙的地方:
UIStackView
旨在适应所有区域。
- 在转换过程中,
UIScrollView
将尝试调整其边界大小以适应导航栏(或 macOS 应用程序中的工具栏)下方的新 gained/lost 区域。
不幸的是,这会造成无限循环。我对 UIScrollView
及其 adjustedContentInset
不是很熟悉,但是从我在其 layoutSubviews
方法中的日志中,我看到了以下行为:
- 放大window.
UIScrollView
尝试缩小其边界(因为不需要工具栏下方的区域)。
UIStackView
如下。
- 不知为何
UIScrollView
不满意,决定恢复到更大的范围。这对我来说很奇怪,因为我从日志中看到的是 UIScrollView.bounds.height == UIStackView.bounds.height
.
UIStackView
如下。
- 然后循环到第2步。
在我看来,两个步骤可以解决问题:
- 将
UIStackView.top
对齐到 UIScrollView.topMargin
。
- 将
contentInsetAdjustmentBehavior
设置为 .never
。
这里我关注的是一个垂直增长的垂直滚动视图 UIStackView
。对于水平对,相应地更改代码。
希望它对以后的任何人都有帮助。在 Internet 上找不到任何人提到这个,我花了很长时间才弄清楚发生了什么。
我给你正确的解决方案
为Xcode11+
第 1 步:
添加 ScrollView 并调整其大小
第 2 步:
为 ScrollView
添加 Constraints
第 3 步:
添加一个 StackView 到 ScrollView,并调整它的大小。
第 4 步:
为 StackView 添加约束(Stask View -> Content Layout Guide -> "Leading, Top, Trailing, Bottom")
步骤 4.1:
正确的约束 -> Constant (... -> Constant = 0)
第 5 步:
为 StackView 添加约束(Stask View -> Frame Layout Guide -> "Equal Widths")
第 6 步示例:
添加两个带有 HeightConstraints 和 运行 的 UIView
希望对喜欢的你有用
在我的例子中,stackView 中的视图数量是可变的,我想将项目居中。因此,例如,对于 stackView 中的一个视图,我希望该视图位于屏幕中间,如果所有视图都无法容纳在屏幕内,我希望该视图是可滚动的。
这是我的视图层次结构。
所以我为按钮设置了固定宽度,然后,对于 stackView:
- 与按钮相同的固定宽度,但优先级为 650。
- 将 X 中心与 containerView 对齐
- containerView 的尾部 >= 0 和前导 >= 0
- 底部和顶部 space 到 containerView
对于 containerView:
- 到超级视图的尾部、前导、底部、顶部、等高、等宽(250 优先级)
- 固定高度
对于scrollView:
- 父视图的尾随、前导、底部、顶部
滚动视图也嵌入到具有前导和尾随约束的视图中。
关于我用来处理这个问题的代码:
for index in 0...array.count - 1 {
if index == 0 {
firstButton.setTitle(title, for: .normal)
} else {
let button = UIButton()
button.setTitle(title, for: .normal)
stackView.addArrangedSubview(button)
stackView.setNeedsLayout()
}
}
containerView.layoutIfNeeded()
stackView.distribution = .fillEqually
stackView.spacing = 10
stackView.alignment = .fill
stackview 中的动态元素嵌入 scrollview 的一种简单方法。在 XIB 中,在 UIScrollView 中添加一个 UIStackView,并添加堆栈视图适合滚动视图(顶部、底部、前导、尾部)的约束,并添加一个约束以匹配它们之间的水平中心。但将最后一个约束标记为“在构建时删除”。它让 XIB 开心并避免错误。
水平滚动示例:
然后:
然后在您的代码中,只需像这样在堆栈视图中添加按钮等元素:
array.forEach { text in
let button = ShadowButton(frame: .zero)
button.setTitle(text, for: .normal)
myStackView.addArrangedSubview(button)
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
button.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
每个人在使用 Storyboard 执行此操作时似乎都错过了修复乘数!
当您按照任何人教程中的上述步骤并将常量重置为 0 时,还要检查乘数并将其重置为 1,当视觉链接保持原位时,它会采取一些其他因素
我发现我可以简单地使用
在 UIStackView 中挤压或拉伸 LOOOOOOOOOOOOONG 文本块
简单
向滚动视图添加约束
左上右下,缺点 0
向指向滚动条内容布局指南的堆栈视图添加约束
然后根据框架布局指南添加等宽或等高约束。
Pick : 如果内容需要垂直滚动,则为宽度,如果需要水平滚动,则为高度。
关键来了。编辑每个约束并将常量重置为 0 并将乘数设置回 1!!!!!
如果你不这样做,它会变得不稳定
如果可行,您可以单击内部内容并滚动鼠标
假设我在 UIStackView 中添加了更多可以显示的视图,我如何才能使 UIStackView
滚动?
正如 Eik 所说,UIStackView
和 UIScrollView
一起玩得很好,参见 here。
关键是 UIStackView
处理变量 height/width 不同的内容,然后 UIScrollView
很好地完成 scrolling/bouncing 内容的工作:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
只需将此添加到 viewdidload
:
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
如果有人正在寻找解决方案无需代码,我创建了一个示例来完全在故事板中使用自动布局来完成此操作。
您可以从 github.
获取基本上,要重新创建示例(用于垂直滚动):
- 创建一个
UIScrollView
,并设置其约束。 - 在
UIScrollView
中添加一个 - 设置约束:
Leading
、Trailing
、Top
&Bottom
应该等于UIScrollView
- 在
UIStackView
和UIScrollView
之间设置一个相等的Width
约束。 - 在
UIStackView
上设置轴 = 垂直、对齐 = 填充、分布 = 等间距和间距 = 0
- 在
UIStackView
中添加 - 运行
UIStackView
UIViews
个数
将步骤4中的Width
换成Height
,并在步骤5中设置Axis
= Horizontal
,得到一个横向的UIStackView。
这里投票最高的答案中的限制条件对我有用,我在下面粘贴了限制条件的图像,这是在我的情节提要中创建的。
我确实遇到了两个问题,但其他人应该知道:
添加与已接受答案中的约束类似的约束后,我会收到红色自动布局错误
Need constraints for: X position or width
。这是通过添加 UILabel 作为堆栈视图的子视图解决的。我正在以编程方式添加子视图,因此故事板上最初没有子视图。要消除自动布局错误,请将子视图添加到故事板,然后在加载时将其删除,然后再添加真正的子视图和约束。
我最初尝试将
UIButtons
添加到 UIStackView。按钮和视图会加载,但 滚动视图不会滚动 。这是通过将UILabels
添加到堆栈视图而不是按钮来解决的。使用相同的约束,此视图层次结构与 UILabels 滚动,但 UIButtons 不滚动。我对这个问题感到困惑,因为 UIButtons do 似乎有一个 IntrinsicContentSize(由 Stack View 使用)。如果有人知道为什么按钮不起作用,我很想知道为什么。
这是我的视图层次结构和约束,供参考:
Apple 的自动布局指南包括关于 Working with Scroll Views 的整个部分。一些相关的片段:
- 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.
此外:
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.
总而言之,滚动视图的内容视图(在本例中为堆栈视图)必须固定到其边缘 并且 的宽度 and/or 高度否则会受到限制.这意味着堆栈视图的内容必须(直接或间接地)在需要滚动的方向上受到约束,例如,这可能意味着向垂直滚动堆栈视图内的每个视图添加高度约束。以下是如何允许包含堆栈视图的滚动视图的垂直滚动的示例:
// 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
如果您有将堆栈视图在滚动视图内垂直居中的限制,只需将其删除。
2020 年最新信息。
100% 故事板或 100% 代码。
这个例子是垂直的:
这是最简单的解释:
有空白full-screen场景
添加滚动视图。 Control-drag从滚动视图到基本视图,添加left-right-top-bottom,全部为零。
在滚动视图中添加堆栈视图。 Control-drag从堆栈视图到滚动视图,添加left-right-top-bottom,全部为零。
在堆栈视图中放置两个或三个标签。
为清楚起见,将标签的背景色设为红色。将标签高度设置为 100.
现在设置每个 UILabel 的宽度:
令人惊讶的是,control-drag从
UILabel
到滚动视图,不是到堆栈视图,select等宽.
重复:
不要控制从 UILabel 到 UILabel 的 parent 的拖动 - 转到 grandparent。 (换句话说,一路走到滚动视图,不要走到堆栈视图。)
就这么简单。这就是秘密。
Secret tip - Apple bug:
It will not work with only one item! Add a few labels to make the demo work.
大功告成。
提示:您必须为每个新项目添加高度。任何滚动堆栈视图中的每个项目都必须具有固有大小(例如标签)或添加显式高度限制。
替代方法:
回顾一下上面的方法:令人惊讶的是,将标签的宽度设置为滚动视图(而不是堆栈视图)的宽度。
这是另一种方法...
从堆栈视图拖动到滚动视图,并添加“宽度相等”约束。这看起来很奇怪,因为 您已经固定了 left-right,但是 您就是这样做的。不管看起来多么奇怪,这就是秘密。
所以你有两个选择:
- 令人惊讶的是,将stackview中每个项目的宽度设置为scrollview grandparent的宽度(不是stackviewparent).
或
- 令人惊讶的是,将堆栈视图的“宽度等于”设置为滚动视图 - 即使你确实有左右边缘无论如何固定到滚动视图的堆栈视图。
明确地说,只执行其中一种方法,不要同时执行两种方法。
你可以尝试 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];
// ...
首先也是最重要的是设计你的视图,最好是在 Sketch 之类的东西中,或者得到一个 关于您想要什么作为可滚动内容的想法。
之后使视图控制器自由形式(从属性中选择 inspector) 并根据内在内容设置高度和宽度 您的视图大小(从大小检查器中选择)。
之后在视图控制器中放置一个滚动视图,这是一个 逻辑,我发现它几乎一直在 iOS 中工作(它可能需要查看该视图的文档 class 可以通过命令获得该视图并单击 class或通过谷歌搜索)
如果您正在使用两个或多个视图,则首先从一个视图开始,该视图已被较早介绍或更原始,然后转到已被介绍的视图 后来或更现代。所以这里因为滚动视图已经 先介绍一下,先从scroll view开始,再到 堆栈视图。这里将滚动视图约束在所有方向 vis-a-vis 其超级视图中设置为零。将所有视图放入此滚动视图中,然后将它们放入堆栈视图中。
在使用堆栈视图时
首先从基础开始(自下而上的方法),即,如果您的视图中有标签、文本字段和图像,则首先布置这些视图(在滚动视图内)和之后将它们放在堆栈视图中。
之后调整堆栈视图的 属性。如果仍未实现所需视图,则使用另一个堆栈视图。
- 如果仍未达到,则使用压缩阻力或内容拥抱优先级进行播放。
- 在此之后向堆栈视图添加约束。
- 还可以考虑使用一个空的 UIView 作为填充视图,如果以上所有方法都没有给出令人满意的结果。
创建视图后,在母堆栈视图和滚动视图之间放置一个约束,同时约束子堆栈视图与母堆栈视图。 希望此时它应该可以正常工作,否则您可能会收到来自 Xcode 的警告并提供建议,阅读它所说的内容并实施这些建议。希望现在你应该有一个符合你期望的工作视图:)。
垂直示例 stackview/scrollview(使用 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)
]
只需确保定义了每个子视图的高度!
我正想做同样的事情并偶然发现了这个 excellent post. 如果您想使用锚点 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
对于嵌套或单个堆栈视图,滚动视图必须与根视图设置固定宽度。滚动视图内部的主堆栈视图必须设置相同的宽度。 [我的滚动视图在 View 下方忽略它]
Set up an equal Width constraint between the UIStackView and 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()
}
水平滚动(UIScrollView 中的 UIStackView)
用于水平滚动。首先,创建一个 UIStackView
和一个 UIScrollView
并按以下方式将它们添加到您的视图中:
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
记得在 UIStackView
和 UIScrollView
上将 translatesAutoresizingMaskIntoConstraints
设置为 false
:
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。
文本插入
您可能会发现一个有用的附加功能是,因为 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
在您的场景中放置一个滚动视图,并调整其大小使其充满场景。然后,在滚动视图中放置一个堆栈视图,并将添加项目按钮放置在堆栈视图中。一切就绪后,设置以下约束:
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 应用程序支持 window 调整大小,因此您的 UIStackView
可能会从不可滚动状态转换为可滚动状态,反之亦然。这里有两个微妙的地方:
UIStackView
旨在适应所有区域。- 在转换过程中,
UIScrollView
将尝试调整其边界大小以适应导航栏(或 macOS 应用程序中的工具栏)下方的新 gained/lost 区域。
不幸的是,这会造成无限循环。我对 UIScrollView
及其 adjustedContentInset
不是很熟悉,但是从我在其 layoutSubviews
方法中的日志中,我看到了以下行为:
- 放大window.
UIScrollView
尝试缩小其边界(因为不需要工具栏下方的区域)。UIStackView
如下。- 不知为何
UIScrollView
不满意,决定恢复到更大的范围。这对我来说很奇怪,因为我从日志中看到的是UIScrollView.bounds.height == UIStackView.bounds.height
. UIStackView
如下。- 然后循环到第2步。
在我看来,两个步骤可以解决问题:
- 将
UIStackView.top
对齐到UIScrollView.topMargin
。 - 将
contentInsetAdjustmentBehavior
设置为.never
。
这里我关注的是一个垂直增长的垂直滚动视图 UIStackView
。对于水平对,相应地更改代码。
希望它对以后的任何人都有帮助。在 Internet 上找不到任何人提到这个,我花了很长时间才弄清楚发生了什么。
我给你正确的解决方案
为Xcode11+
第 1 步: 添加 ScrollView 并调整其大小
第 2 步: 为 ScrollView
添加 Constraints第 3 步: 添加一个 StackView 到 ScrollView,并调整它的大小。
第 4 步: 为 StackView 添加约束(Stask View -> Content Layout Guide -> "Leading, Top, Trailing, Bottom")
步骤 4.1: 正确的约束 -> Constant (... -> Constant = 0)
第 5 步: 为 StackView 添加约束(Stask View -> Frame Layout Guide -> "Equal Widths")
第 6 步示例:
添加两个带有 HeightConstraints 和 运行 的 UIView
希望对喜欢的你有用
在我的例子中,stackView 中的视图数量是可变的,我想将项目居中。因此,例如,对于 stackView 中的一个视图,我希望该视图位于屏幕中间,如果所有视图都无法容纳在屏幕内,我希望该视图是可滚动的。
这是我的视图层次结构。
所以我为按钮设置了固定宽度,然后,对于 stackView:
- 与按钮相同的固定宽度,但优先级为 650。
- 将 X 中心与 containerView 对齐
- containerView 的尾部 >= 0 和前导 >= 0
- 底部和顶部 space 到 containerView
对于 containerView:
- 到超级视图的尾部、前导、底部、顶部、等高、等宽(250 优先级)
- 固定高度
对于scrollView:
- 父视图的尾随、前导、底部、顶部
滚动视图也嵌入到具有前导和尾随约束的视图中。
关于我用来处理这个问题的代码:
for index in 0...array.count - 1 {
if index == 0 {
firstButton.setTitle(title, for: .normal)
} else {
let button = UIButton()
button.setTitle(title, for: .normal)
stackView.addArrangedSubview(button)
stackView.setNeedsLayout()
}
}
containerView.layoutIfNeeded()
stackView.distribution = .fillEqually
stackView.spacing = 10
stackView.alignment = .fill
stackview 中的动态元素嵌入 scrollview 的一种简单方法。在 XIB 中,在 UIScrollView 中添加一个 UIStackView,并添加堆栈视图适合滚动视图(顶部、底部、前导、尾部)的约束,并添加一个约束以匹配它们之间的水平中心。但将最后一个约束标记为“在构建时删除”。它让 XIB 开心并避免错误。
水平滚动示例:
然后:
然后在您的代码中,只需像这样在堆栈视图中添加按钮等元素:
array.forEach { text in
let button = ShadowButton(frame: .zero)
button.setTitle(text, for: .normal)
myStackView.addArrangedSubview(button)
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
button.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
每个人在使用 Storyboard 执行此操作时似乎都错过了修复乘数! 当您按照任何人教程中的上述步骤并将常量重置为 0 时,还要检查乘数并将其重置为 1,当视觉链接保持原位时,它会采取一些其他因素
我发现我可以简单地使用
在 UIStackView 中挤压或拉伸 LOOOOOOOOOOOOONG 文本块简单 向滚动视图添加约束 左上右下,缺点 0
向指向滚动条内容布局指南的堆栈视图添加约束
然后根据框架布局指南添加等宽或等高约束。 Pick : 如果内容需要垂直滚动,则为宽度,如果需要水平滚动,则为高度。
关键来了。编辑每个约束并将常量重置为 0 并将乘数设置回 1!!!!!
如果你不这样做,它会变得不稳定
如果可行,您可以单击内部内容并滚动鼠标