UIStackView可以滚动吗?

比方说,我已经在UIStackView中添加了更多的可以显示的视图,我可以如何使UIStackView滚动?

如果有人正在寻找一个没有代码的解决scheme,我创build了一个例子,使用自动布局,完全在故事板中完成。

你可以从github获得它。

基本上,重新创build这个例子:

  1. 创build一个UIScrollView ,并设置其约束。
  2. 添加一个UIStackViewUIScrollView
  3. 设置约束: LeadingTrailingTopBottom应该和UIScrollView
  4. 在UIStackView和UIScrollView之间设置一个相等的Width约束。
  5. 在UIStackView上设置Axis = Vertical,Alignment = Fill,Distribution = Equal Spacing和Spacing = 0
  6. 添加一些UIStackViewUIStackView

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 

正如Eik所说,UIStackView和UIScrollView一起玩很好,看到这里 。

关键是UIStackView处理不同内容的variables高度/宽度,然后UIScrollView在滚动/反弹内容方面做得很好:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height) } 

这里顶部答案的答案约束在我这里工作,我已经粘贴了下面的约束图像,在我的故事板中创build。

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

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

    我以编程方式添加了子视图,所以我原来在故事板上没有子视图。 为了摆脱自动布局错误,添加一个子视图到故事板,然后在加载之前删除它,然后添加您的真实子视图和约束。

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

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

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

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

我期待着做同样的事情,并偶然发现这个优秀的职位。 如果你想以编程方式使用锚API来做到这一点,

总结一下,将UIStackViewembedded到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 

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

示例代码(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]; // ... 

以下是最简单的解释:

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

  2. 添加滚动视图。 控制 – 从滚动视图拖动到基本视图 ,添加左上angular,全零。

  3. 在滚动视图中添加一个堆栈视图。 控制 – 从堆栈视图拖动到滚动视图 ,添加左上angular,全零。

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

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

  1. 现在设置UILabel的宽度:

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

重复:

不要控制从UILabel拖到UILabel的父母 – 去祖父母。 (换句话说,一直走到滚动视图,不要去堆栈视图。)

就这么简单。 这是秘密。

  1. 接下来,你必须点击一个UILabel,你必须从字面上点击复制粘贴几次。 它不会只有一个项目。 (不要点击“复制”,点击“复制然后粘贴”)。

你完成了。 就这么简单。

提示:尝试添加一个新的项目到堆栈视图,比如一个UIView(可能被用作空间)。 请注意,一切都出错了。 事实上,你必须给每一个新的项目添加一个高度 (比如“100”)。 每当你添加一个新的项目, 你必须以某种方式给它一个高度


另一种看待它的方法是:

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

交替…

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

从堆栈视图拖动到滚动视图,并添加一个“宽度相等”约束。 这似乎很奇怪,因为你已经固定左右 ,但这是你如何做到这一点 。 不pipe多么奇怪,这似乎就是秘密。

所以你有两个select:

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

要么

  1. 令人惊讶的是,将stackview的“宽度相等”设置为滚动视图 – 即使您确实将stackview的左右边缘固定到滚动视图。

要清楚,做其中的一种方法,不要两者兼而有之。

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

垂直堆栈视图/滚动视图示例(使用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) ] 

只要确保你的每个子视图的高度已经被定义了!

  1. 首先,最重要的是devise你的观点,最好是像素描,或者你想要一个可以滚动的内容。

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

  3. 之后,在视图控制器放置一个滚动视图,这是一个逻辑,我发现几乎所有的时间在iOS(可能需要通过该视图类的文档,可以通过命令+点击获得该类或通过Googlesearch)

    如果您正在处理两个或更多的视图,那么首先从一个视图开始,这个视图已经被引入了,或者是更原始的视图,然后转到稍后介绍的视图或者更现代的视图。 所以在这里,由于首先介绍了滚动视图,首先从滚动视图开始,然后进入堆栈视图。 这里把所有方向的滚动视图约束都设置为零。 把所有的视图放在这个滚动视图中,然后把它们放在堆栈视图中。

使用堆栈视图时

  • 首先从头开始(底部向上的方法),即,如果在视图中有标签,文本字段和图像,则先布局这些视图(在滚动视图内),然后将它们放入堆栈视图中。

  • 之后,调整堆栈视图的属性。 如果所需的视图仍然没有实现,那么使用另一个堆栈视图。

  • 如果还没有实现,那么玩压缩或内容拥抱优先。
  • 在此之后,添加到堆栈视图的约束。
  • 如果以上所有内容都没有给出令人满意的结果,也可以考虑使用空的UIView作为填充视图。

在完成视图之后,在母堆栈视图和滚动视图之间添加一个约束,而用母堆栈视图约束子视图的子视图。 希望这个时候应该可以正常工作,否则你可能会得到Xcode给出的build议,阅读它所说的内容并执行它们。 希望现在你应该有一个工作的看法,根据您的期望:)。

把它放到一个UIScrollView