UIStackView可以滚动吗?

时间:2015-07-28 06:36:33

标签: ios uiscrollview uistackview

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

20 个答案:

答案 0 :(得分:459)

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

您可以从github获取。

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

  1. 创建UIScrollView,并设置其约束。
  2. UIStackView添加到UIScrollView
  3. 设置约束:LeadingTrailingTop& Bottom应与UIScrollView
  4. 中的Width相同
  5. UIStackViewUIScrollView之间设置相等的UIStackView约束。
  6. UIViews
  7. 上设置Axis = Vertical,Alignment = Fill,Distribution = Equal Spacing和Spacing = 0
  8. UIStackView
  9. 添加一些.map()
  10. 运行

答案 1 :(得分:37)

Apple的自动布局指南包含Working with Scroll Views的整个部分。一些相关的片段:

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

此外:

  

您的布局必须完全定义内容视图的大小(除外   在步骤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

答案 2 :(得分:13)

正如Eik所说,UIStackView和UIScrollView很好地协同工作,请参阅here

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

cp "$f" "$destinationPath/archive"

答案 3 :(得分:12)

最高投票答案中的限制对我有用,并且我已经粘贴了下面约束的图像,如我的故事板中所创建的那样。

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

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

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

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

    我对此问题感到困惑,因为UIButtons 似乎有一个IntrinsicContentSize(由Stack View使用)。如果有人知道按钮为什么不起作用,我很想知道原因。

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

    constraints for stack view in scroll view[1]

答案 4 :(得分:9)

我为您提供正确的解决方案

对于Xcode 11 +

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

enter image description here enter image description here

步骤2: 为滚动视图添加约束

enter image description here

第3步: StackView 添加到ScrollView中,并调整其大小。

enter image description here

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

enter image description here enter image description here

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

enter image description here enter image description here

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

enter image description here enter image description here

第6步示例: 添加两个具有 HeightConstraints RUN 的UIView enter image description here enter image description here

我希望它将对您有用

答案 5 :(得分:9)

我本来想做同样的事情并偶然发现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

答案 6 :(得分:5)

只需将其添加到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

答案 7 :(得分:3)

水平滚动(UIScrollView中的UIStackView)

用于水平滚动。首先,创建一个{ model: models.Categories, as: 'nestedCategories', include: [ { model: models.Categories, as: 'nestedCategories' } ] } 和一个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 方法将子视图添加到UIStackView。

文字插图

您可能会发现有用的另一个功能是,由于addArrangedSubview:被保存在UIStackView中,因此您现在可以访问文本插图,使外观看起来更漂亮。

UIScrollView

答案 8 :(得分:2)

这是最简单的解释:

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

  2. 添加滚动视图。从滚动视图控制拖动到基本视图,添加左右上下,全部为零。

  3. 在滚动视图中添加堆栈视图。从堆栈视图控制拖动到滚动视图,添加左右上下,全部为零。

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

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

    1. 现在设置UILabel的宽度:

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

    2. 重复:

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

      就这么简单。这是秘密。

      1. 接下来,您必须点击一个UILabel,并且您必须按字面意义复制粘贴几次。只有一个项目无效。 (不要点击“复制”,点击“复制然后粘贴”。)
      2. 你已经完成了。就这么简单。

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

        另一种看待它的方式:

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

        可替换地...

        请注意,堆栈视图左右固定到其父级滚动视图。试试这个:

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

        所以你有两个选择:

        1. 令人惊讶的是,将UILabels的宽度设置为滚动视图祖父母的宽度( 不是stackview父级 )。
          1. 令人惊讶的是,将stackview的“宽度相等”设置为滚动视图 - 即使 您仍然将stackview的左右边缘固定到scrollview上
          2. 要清楚,请执行其中一种方法,不要同时执行这两种操作。

答案 9 :(得分:2)

您可以尝试 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]; 
// ...

答案 10 :(得分:2)

为macOS Catalyst添加了一些新观点。由于macOS应用支持窗口大小调整,因此您的UIStackView可能会从不可滚动状态转换为可滚动状态,反之亦然。这里有两点微妙的事情:

  • UIStackView旨在适应所有可能的区域。
  • 在过渡期间,UIScrollView将尝试调整其边界大小,以解决导航栏(对于macOS应用程序为工具栏)下方新增加/丢失的区域。

不幸的是,这将创建一个无限循环。我对UIScrollView及其adjustedContentInset并不十分熟悉,但是从其layoutSubviews方法的登录中,我看到了以下行为:

  • 一个扩大窗口。
  • UIScrollView尝试缩小其边界(因为不需要工具栏下方的区域)。
  • UIStackView
  • 不知何故UIScrollView不满意,因此决定恢复到更大的范围。这对我来说很奇怪,因为从日志中看到的是UIScrollView.bounds.height == UIStackView.bounds.height
  • UIStackView
  • 然后循环到步骤2。

在我看来,两个步骤可以解决此问题:

  • UIStackView.topUIScrollView.topMargin对齐。
  • contentInsetAdjustmentBehavior设置为.never

在这里,我关注的是UIStackView垂直增长的垂直滚动视图。对于水平对,请相应地更改代码。

希望它对以后的任何人都有帮助。在互联网上找不到任何人提及此事,这花了我很长时间才能弄清发生了什么。

答案 11 :(得分:0)

创建的示例项目同时处理垂直和水平轴滚动。

https://gitlab.com/muhasturk/bmh.example.stackinsidescroll.ios

答案 12 :(得分:0)

就我而言,stackView 中的视图数量是可变的,我想将项目居中。因此,例如,stackView 中有一个视图,我希望该视图位于屏幕中间,如果所有视图都无法容纳在屏幕内,我希望该视图可滚动。

这是我的视图层次结构。

enter image description here

所以我为按钮设置了固定宽度,然后为 stackView

  • 与按钮具有相同的固定宽度,但优先级为 650。
  • 将 X 中心与 containerView 对齐
  • 尾随 >= 0 和前导 >= 0 到 containerView
  • containerView 的底部和顶部空间

enter image description here

对于 containerView

  • 尾随、前导、底部、顶部、等高、等宽(250 优先级)到超级视图
  • 固定高度

enter image description here

对于 scrollView

  • 尾随、前导、底部、顶部到超级视图

scrollView 也嵌入在具有前导和尾随约束的视图中。

enter image description here

关于我用来解决这个问题的代码:

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

答案 13 :(得分:0)

在场景上放置滚动视图,并调整其大小以使其充满场景。然后,将堆栈视图放置在滚动视图内,然后将添加项目按钮放置在堆栈视图内。一切就绪后,设置以下约束:

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

enter image description here

代码:Stack View.Width = Scroll View.Width是关键。

答案 14 :(得分:0)

如果有人在寻找水平滚动视图

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()

 }

答案 15 :(得分:0)

对于嵌套或单个堆栈视图,滚动视图必须使用根视图设置固定宽度。滚动视图内部的主堆栈视图必须设置相同的宽度。 [我的滚动视图低于视图忽略它]

  

在UIStackView和之间设置一个相等的宽度约束   的UIScrollView。

enter image description here

答案 16 :(得分:0)

垂直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)
]

确保定义了每个子视图的高度!

答案 17 :(得分:0)

  1. 首先设计你的视图,最好是像Sketch或者得到一个 你想要什么作为可滚动内容的想法。

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

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

    如果您正在使用两个或更多视图,那么首先从一个视图开始,该视图已在前面介绍过或更原始,然后转到已经介绍的视图 以后或更现代。所以这里是滚动视图 首先介绍,首先从滚动视图开始,然后转到 堆栈视图。这里将滚动视图约束在其超视图的所有方向上设置为零。将所有视图放在此滚动视图中,然后将它们放在堆栈视图中。

  4. 使用堆栈视图时

    • 首先从地面开始(自下而上),即,如果您在视图中有标签,文本字段和图像,然后首先布置这些视图(在滚动视图内),然后放置它们在堆栈视图中。

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

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

    在创建视图后,在母堆栈视图和滚动视图之间设置约束,而约束子视图使用母堆栈视图堆栈视图。 希望到这个时候它应该可以正常工作,或者你可以从Xcode发出警告,提出建议,阅读它所说的内容并实现它们。希望你现在应该有一个符合你期望的工作观点:)。

答案 18 :(得分:0)

如果您有一个约束来将堆栈视图垂直居中在滚动视图中,只需将其删除即可。

答案 19 :(得分:-12)

将其放入UIScrollView ...