假设我在UIStackView中添加了可以显示的更多视图,如何进行UIStackView
滚动?
假设我在UIStackView中添加了可以显示的更多视图,如何进行UIStackView
滚动?
Answers:
万一有人在寻找没有代码的解决方案,我创建了一个示例,使用自动版式在情节提要中完全做到这一点。
您可以从github获得它。
基本上,重新创建示例(用于垂直滚动):
UIScrollView
,并设置其约束。UIStackView
到UIScrollView
Leading
,Trailing
,Top
和Bottom
应该等于从那些UIScrollView
Width
在UIStackView
和之间设置相等的约束UIScrollView
。UIStackView
UIViews
的UIStackView
交换Width
为Height
在步骤4中,和组Axis
= Horizontal
在步骤5中,获得一个水平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.
仅当您同时为堆栈视图设置宽度和高度限制时,该错误才会消失,这将禁用垂直滚动。这段代码对您仍然有用吗?
这里投票最多的答案中的约束对我有用,并且我粘贴了以下约束的图像,如在情节提要中创建的那样。
我确实遇到了两个问题,尽管其他人应该意识到:
在添加与接受的答案中的约束相似的约束之后,我将得到红色的autolayout错误Need constraints for: X position or width
。通过添加UILabel作为堆栈视图的子视图来解决此问题。
我是通过编程方式添加子视图的,因此故事板最初没有子视图。要消除自动布局错误,请在情节提要中添加一个子视图,然后在加载时将其删除,然后再添加真正的子视图和约束。
我最初试图添加UIButtons
到UIStackView中。按钮和视图将加载,但滚动视图将不会滚动。通过添加UILabels
到堆栈视图而不是按钮来解决此问题。使用相同的约束,带有UILabels的视图层次结构会滚动,但UIButtons不会。
我对此问题感到困惑,因为UIButton 似乎确实具有IntrinsicContentSize(由Stack View使用)。如果有人知道为什么按钮不起作用,我很想知道为什么。
这是我的视图层次结构和约束,以供参考:
正如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
全屏空白
添加滚动视图。按住Control键从滚动视图拖动到基本视图,然后将left-right-top-bottom添加为零。
在滚动视图中添加一个堆栈视图。按住Control键从堆栈视图拖动到滚动视图,将left-right-top-bottom添加为零。
在堆栈视图中放置两个或三个标签。
为了清楚起见,请将标签的背景色设为红色。将标签高度设置为100。
现在设置每个UILabel 的宽度:
令人惊讶的是,按住Control键从中拖动UILabel
到滚动视图,而不是堆栈视图,然后选择width相等。
重复:
就这么简单。那是秘密。
秘诀-Apple错误:
这是行不通的,只有一个项目!添加一些标签以使演示工作。
你完成了。
提示:您必须为每个新项目添加一个高度。任何滚动堆栈视图中的每个项目都必须具有固有尺寸(例如标签)或添加显式的高度约束。
替代方法:
在上面的代码中:令人惊讶的是,将UILabels的宽度设置为滚动视图(而不是堆栈视图)的宽度。
交替...
因此,您有两种选择:
要么
为了清楚起见,请选择其中一种方法,不要同时使用。
用于水平滚动。首先,创建一个UIStackView
和一个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中。
您可能会发现有用的另一个功能是,由于该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
只需将其添加到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获得。
示例代码(快速)
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];
// ...
垂直stackview / scrollview的示例(使用EasyPeasy
for自动布局):
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中几乎一直都在工作(它可能需要仔细阅读该视图类的文档,可以通过命令+单击该课程或通过谷歌搜索)
如果使用两个或多个视图,则首先从一个较早引入的视图或更原始的视图开始,然后转到一个较晚引入的视图或更现代的视图。因此,在这里,因为首先引入了滚动视图,所以先从滚动视图开始,然后再进入堆栈视图。在此,将滚动视图约束与其超级视图在所有方向上都设为零。将所有视图放入此滚动视图,然后将其放入堆栈视图。
在使用堆栈视图时
首先从基础开始(从下至上的方法),即,如果视图中有标签,文本字段和图像,则先布局这些视图(在滚动视图内部),然后将它们放置在堆栈视图中。
之后,调整堆栈视图的属性。如果仍然无法实现所需的视图,请使用另一个堆栈视图。
创建视图之后,在母堆栈视图和滚动视图之间放置一个约束,而约束子堆栈视图与母堆栈视图一起放置。希望这次可以正常工作,否则您可能会从Xcode收到警告,给出建议,阅读建议内容并实施。希望现在您应该按照自己的期望进行工作:)。
对于嵌套或单个堆栈视图,滚动视图必须使用根视图设置为固定宽度。滚动视图内部的主堆栈视图必须设置相同的宽度。[我的滚动视图在视图的下面,将其忽略]
在UIStackView和UIScrollView之间设置相等的Width约束。
如果有人在寻找水平滚动视图
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
会从不可滚动状态转换为可滚动状态,反之亦然。这里有两件事:
UIStackView
被设计为适合所有区域。UIScrollView
将尝试调整其边界大小,以解决导航栏(对于macOS应用程序为工具栏)下方新获得/丢失的区域。不幸的是,这将造成无限循环。我UIScrollView
对它及其不是很熟悉adjustedContentInset
,但是从其layoutSubviews
方法登录后,我看到了以下行为:
UIScrollView
尝试缩小其边界(因为不需要工具栏下方的区域)。UIStackView
如下。UIScrollView
,并决定恢复到更大的界限。这让我感到很奇怪,因为我从日志中看到的是UIScrollView.bounds.height == UIStackView.bounds.height
。UIStackView
如下。在我看来,两个步骤可以解决此问题:
UIStackView.top
到UIScrollView.topMargin
。contentInsetAdjustmentBehavior
到.never
。在这里,我关注的是垂直滚动的视图以及垂直增长的视图UIStackView
。对于水平对,请相应地更改代码。
希望它对将来的任何人有帮助。在互联网上找不到任何人提及此事,这花了我很长时间才能弄清发生了什么。