UIStackView可以滚动吗?

its*_*ode 174 uiscrollview ios uistackview

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

Arj*_*jan 503

如果有人在寻找没有代码的解决方案,我创建了一个示例,使用自动布局在故事板中完全执行此操作.

你可以从github得到它.

基本上,要重新创建示例:

  1. 创建一个UIScrollView,并设置其约束.
  2. 添加UIStackViewUIScrollView
  3. 设定限制:Leading,Trailing,TopBottom应该等于从那些UIScrollView
  4. WidthUIStackView和之间设置一个相等的约束UIScrollView.
  5. 设置Axis = Vertical,Alignment = Fill,Distribution = Equal Spacing,Spacing = 0 on UIStackView
  6. 添加了许多UIViewsUIStackView

  • 谢谢!"4.在UIStackView和UIScrollView之间设置一个相等的宽度约束." 是关键;) (49认同)
  • 6号也很重要.想要在代码中添加所有视图,但随后自动布局显示IB中缺少约束. (15认同)
  • 嗨,似乎这个解决方案不适用于水平滚动.在步骤4中,我假设设置相等的高度而不是设置相等的宽度,而Axis = Horizo​​ntal.我试过了,但没有用. (11认同)
  • 添加约束以使stackview和scrollview具有相等的宽度将从界面构建器中删除警告,但随后将禁用滚动.仅当滚动视图内的内容视图比滚动视图_larger_时才会滚动! (4认同)
  • 详细说明第6点.如果堆栈视图没有元素但所有约束都已到位,则会出现"滚动视图需要约束Y位置或高度".只是在堆栈视图中添加一个Label就会使这个警告消失! (4认同)
  • 我正在以编程方式添加我的 UIScrollView 和 UIStackView。Arjan 在 Swift 4 上为我工作的步骤,但我只需要在构建我的 UIStackView 时再添加 1 行代码:`myStackView.translatesAutoresizingMaskIntoConstraints = false` (2认同)

tit*_*coy 41

Apple的"自动布局指南"包含有关使用滚动视图的整个部分.一些相关的片段:

  1. 将内容视图的顶部,底部,前导和尾部边缘固定到滚动视图的相应边缘.内容视图现在定义滚动视图的内容区域.
  2. (可选)要禁用水平滚动,请将内容视图的宽度设置为等于滚动视图的宽度.内容视图现在水平填充滚动视图.
  3. (可选)要禁用垂直滚动,请将内容视图的高度设置为等于滚动视图的高度.内容视图现在水平填充滚动视图.

此外:

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

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

// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true

// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但是省略高度约束(允许垂直滚动)会在 Storyboard 中产生这个错误:`需要约束:Y 位置或高度。` 只有当你为堆栈视图设置宽度和高度约束时,这个错误才会消失,禁用垂直滚动。这段代码对你还有用吗? (2认同)

小智 33

我向您展示正确的解决方案

对于 Xcode 11+

第 1 步: 添加ScrollView并调整其大小

在此处输入图片说明在此处输入图片说明

第 2 步:为 ScrollView 添加约束

在此处输入图片说明

第三步:在 ScrollView 中 添加一个StackView,并调整它的大小。

在此处输入图片说明

第 4 步: 为 StackView 添加约束(Stask View -> Content Layout Guide -> "Leading, Top, Trailing, Bottom"

在此处输入图片说明 在此处输入图片说明

步骤 4.1: 正确的约束 ->常量(... -> 常量 = 0)

在此处输入图片说明 在此处输入图片说明

第 5 步: 为 StackView 添加约束(Stask View -> Frame Layout Guide -> "Equal Widths ")

在此处输入图片说明 在此处输入图片说明

步骤 6 示例: 添加两个带有HeightConstraintsRUN 的UIView(s) 在此处输入图片说明 在此处输入图片说明

我希望它对你有用

  • 这是 Xcode 11 和 12 的正确过程。有几个步骤,您必须非常仔细地遵循它们。观看此视频可能会有所帮助:https://www.youtube.com/watch?v=KmE50giVuLA (2认同)

pka*_*amb 14

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

虽然其他人应该知道,我确实遇到了两个问题:

  1. 添加类似于接受的答案中的约束后,我会得到红色自动布局错误Need constraints for: X position or width.这是通过添加UILabel作为堆栈视图的子视图来解决的.

    我正在以编程方式添加子视图,所以我最初在故事板上没有子视图.要消除自动布局错误,请在故事板中添加子视图,然后在添加真实子视图和约束之前将其删除.

  2. 我原本试图添加UIButtons到UIStackView.按钮和视图将加载,但滚动视图不会滚动.这是通过添加UILabels到堆栈视图而不是按钮来解决的.使用相同的约束,此视图层次结构与UILabels滚动但UIButtons不滚动.

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

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

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

  • 您只是节省了我几个小时的头部撞墙和沮丧的心情,我处于完全相同的情况,无法弄清警告的原因以及为什么不能使用按钮。为什么苹果为什么!? (3认同)

小智 13

正如Eik所说,UIStackView和UIScrollView很好地协同工作,请看这里.

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

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)       
}
Run Code Online (Sandbox Code Playgroud)

  • 没有必要结合手动和自动布局来允许可滚动的堆栈视图。您只需要限制堆栈视图的宽度和/或高度。有关详细信息和指向相关 Apple 文档的链接,请参阅我的回答。 (2认同)

Dal*_*zio 9

我本来想做同样的事情,偶然发现了这篇优秀的帖子.如果您想使用锚API以编程方式执行此操作,则可以采用此方法.

总结一下,嵌入你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
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,它们并不是真的重复.另一个问题具体询问如何*以编程方式*而不是这个问题.实际上,这个问题的最佳答案提供了一种实现结果的GUI方法.尽管如此,程序化解决方案可能对某些用户有价值. (8认同)

Fat*_*tie 7

最新的2019。

100%故事板或100%代码。


这是最简单的解释:

  1. 全屏空白

  2. 添加滚动视图。按住Control键从滚动视图拖动到基本视图,然后将left-right-top-bottom添加为零。

  3. 在滚动视图中添加一个堆栈视图。按住Control键从堆栈视图拖动到滚动视图,将left-right-top-bottom添加为零。

  4. 将一个UILabel放入堆栈视图中。

为了清楚起见,请将背景色设为红色;将高度设置为100,并在堆栈视图中将间距设置为20。

  1. 现在设置UILabel的宽度:

    令人惊讶的是,按住Control键从拖动UILabel到滚动视图,而不是堆栈视图,然后选择相等的宽度。

重复:

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

就这么简单。那是秘密。

  1. 接下来,您必须单击一个UILabel,并且必须按实际几次单击复制粘贴。这是行不通的,只有一个项目。(不要单击“复制”,单击“复制然后粘贴”。)

你完成了。就这么简单。

提示:尝试向堆栈视图添加一个新项,例如UIView(可能用作空间)。请注意,一切都会出错。实际上,您必须为每个新项目添加一个高度(例如“ 100”)。每次添加新项目时,都必须以某种方式给它一个高度


另一种查看方式:

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

交替...

请注意,堆栈视图的左侧和右侧固定到其父级(滚动视图)。尝试这个:

从堆栈视图拖动到滚动视图,并添加“宽度相等”约束。这似乎很奇怪,因为您已经左右固定了,但这就是您的做法。无论看起来多么奇怪,这都是秘密。

因此,您有两种选择:

  1. 令人惊讶的是,将UILabels的宽度设置为scrollview祖父母(而不是stackview parent)的宽度。

要么

  1. 出人意料的是,将stackview的“宽度等于”设置为scrollview- 即使您确实确实将stackview的左右边缘固定在scrollview上。

为了清楚起见,请选择其中一种方法,不要同时使用。

  • “100%代码”,代码在哪里? (7认同)
  • 对大文本投了反对票。 (5认同)

Ras*_*d.Z 6

只需将其添加到viewdidload:

let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
Run Code Online (Sandbox Code Playgroud)

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


ske*_*ech 5

水平滚动(UIScrollView中的UIStackView)

用于水平滚动。首先,创建一个UIStackView和一个UIScrollView,然后通过以下方式将它们添加到您的视图中:

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

scrollView.addSubview(stackView)
view.addSubview(scrollView)
Run Code Online (Sandbox Code Playgroud)

记住设置translatesAutoresizingMaskIntoConstraints,以falseUIStackViewUIScrollView

stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
Run Code Online (Sandbox Code Playgroud)

为了使一切正常,的尾随,前导,顶部和底部锚点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
Run Code Online (Sandbox Code Playgroud)

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

stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true
Run Code Online (Sandbox Code Playgroud)

现在锚定您的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 
Run Code Online (Sandbox Code Playgroud)

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

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

topicStackView.spacing = 10
Run Code Online (Sandbox Code Playgroud)

最后,您需要使用该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
Run Code Online (Sandbox Code Playgroud)