UIScrollView 如何将充当容器的子视图约束到所有其他视图?

Posted

技术标签:

【中文标题】UIScrollView 如何将充当容器的子视图约束到所有其他视图?【英文标题】:UIScrollView how do you constrain a sub view that acts a container to all the other views? 【发布时间】:2017-06-07 20:49:20 【问题描述】:

如下所示,我有一个滚动视图,我想将它添加到 UIViewControllers 根视图中。当我将它限制在顶部、右侧、底部和左侧时,我希望看到红色占据整个屏幕。这显然有效,但我想在滚动视图中添加一个子视图来包装所有子视图。我该怎么做呢?

我已经添加了视图并设置了相同的约束,但这次它们是从包装视图设置到 UIScrollView 的边界,并且蓝色背景颜色不会显示在任何地方。如果这是一个坏主意,也请随时指出,但我认为我可以将它限制在底部,它会根据需要自动扩展滚动视图内容大小。当我在没有包装器的情况下在滚动视图中拥有所有子视图并且最后一个视图会扩展内容大小时,这似乎可行。

    scrollView = UIScrollView(frame: view.bounds)

    scrollView?.showsVerticalScrollIndicator = true
    scrollView?.backgroundColor = .red

    scrollView?.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(scrollView!)

    scrollView?.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView?.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    scrollView?.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    scrollView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    //setup wrapper view
    let subviewWrapper = UIView()

    subviewWrapper.translatesAutoresizingMaskIntoConstraints = false

    scrollView?.addSubview(subviewWrapper)

    subviewWrapper.backgroundColor = .blue

    subviewWrapper.topAnchor.constraint(equalTo: (scrollView?.topAnchor)!).isActive = true
    subviewWrapper.leftAnchor.constraint(equalTo: (scrollView?.leftAnchor)!).isActive = true
    subviewWrapper.rightAnchor.constraint(equalTo: (scrollView?.rightAnchor)!).isActive = true
    subviewWrapper.bottomAnchor.constraint(equalTo: (scrollView?.bottomAnchor)!).isActive = true

【问题讨论】:

【参考方案1】:

其实这是一个非常的想法。我总是以这种方式设置我的滚动视图。我通常把视图称为contentView,其实是同一个思路。

你快到了。你还没有给 Auto Layout 任何东西来确定你的 subviewWrapper 的大小。到目前为止,您设置的约束将 subviewWrapper 固定到 scrollView 内容区域的边缘,但这只是确定了一个事实,即作为 subviewWrapper 增长,scrollView 的内容大小将扩大。目前,您的 subviewWrapper 具有 0 宽度和 0 高度,这就是您看不到蓝色的原因。

以下是 3 个示例,说明如何确定 subviewWrapper 的大小。

注意:以下每个示例都是完全独立的。分别查看每一个,当你尝试它们时,记得删除上一个示例添加的约束。


示例 1:将 subviewWrapper 设为 1000 x 1000:

设置约束以使您的 subviewWrapper 1000 x 1000 并且您将看到蓝色并且它会双向滚动。

subviewWrapper.widthAnchor.constraint(equalToConstant: 1000).isActive = true
subviewWrapper.heightAnchor.constraint(equalToConstant: 1000).isActive = true

示例 2:仅垂直滚动,内容大小为 scrollView 高度的 2X:

如果您将 subviewWrapper 的宽度设置为等于 scrollView 的宽度,则它只会垂直滚动。如果您将 subviewWrapper 的高度设置为 scrollView 高度的 2 倍,那么您的蓝色区域将是 scrollView 高度的两倍。

subviewWrapper.widthAnchor.constraint(equalTo: scrollView!.widthAnchor, multiplier: 1.0).isActive = true
subviewWrapper.heightAnchor.constraint(equalTo: scrollView!.heightAnchor, multiplier: 2.0).isActive = true

示例 3:由其子视图设置的 subviewWrapper 的大小:

您还可以通过添加子视图来确定 subviewWrapper 的大小,这些子视图的大小完全指定并从 subviewWrapper 的顶部到底部以链的形式连接,从一边到另一边。如果您这样做,Auto Layout 将有足够的信息来计算您的 subviewWrapper

的大小

在本例中,我在 subviewWrapper 中添加了一个 600 x 600 的黄色正方形,并将其设置为距离每个边缘 100 个点。在没有为 subviewWrapper 显式设置大小的情况下,Auto Layout 可以确定它是800 x 800

let yellowSquare = UIView()

yellowSquare.translatesAutoresizingMaskIntoConstraints = false
yellowSquare.backgroundColor = .yellow
subviewWrapper.addSubview(yellowSquare)

yellowSquare.widthAnchor.constraint(equalToConstant: 600).isActive = true
yellowSquare.heightAnchor.constraint(equalToConstant: 600).isActive = true

yellowSquare.topAnchor.constraint(equalTo: subviewWrapper.topAnchor, constant: 100).isActive = true
yellowSquare.leadingAnchor.constraint(equalTo: subviewWrapper.leadingAnchor, constant: 100).isActive = true
yellowSquare.trailingAnchor.constraint(equalTo: subviewWrapper.trailingAnchor, constant: -100).isActive = true
yellowSquare.bottomAnchor.constraint(equalTo: subviewWrapper.bottomAnchor, constant: -100).isActive = true

【讨论】:

这似乎确实有效,但我似乎无法克服的是我的rightAnchor 似乎无法正常工作。我希望 contentView(subviewWrapper) 将自身约束到 scrollView 的rightAnchor。这并没有给我预期的结果,我必须给它一个 widthAnchor 以匹配 scrollView 宽度。有什么具体原因,还是我做错了什么? 你想通过设置 subviewWrapper 的右锚来实现什么?您是否尝试将滚动限制在垂直方向? 是的,这就是我想要做的。我将它设置为宽度锚,这似乎有效。我只是不明白为什么其他方式不起作用。没什么大不了的,我只是不喜欢它的外观,所以我想我会问是否有特定的原因说明这样做的原因。 这是一件很难理解的事情,但是从scrollView的子视图对scrollView的边缘设置约束实际上是相对于scrollView控制的内容区域而言的。因此,您对0 的右约束仅意味着您的subviewWrapper 将进入内容区域的边缘。但是,由于这是一个滚动视图,因此该内容可以滚动。要保持所有内容可见,您必须确定内容区域的宽度,这可以通过设置宽度约束或将子视图连接成链来完成。

以上是关于UIScrollView 如何将充当容器的子视图约束到所有其他视图?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 XIB 的子视图实现 UIScrollView

UIScrollView + 改变方向 = 混乱的子视图(iPad)

UIScrollView 的子视图应该如何报告它们的 contentSize 范围?

UIViews 是 UIScrollView 的子视图。如何跟踪子视图在定义的矩形内?

如何将 UIPanGestureRecognizer 添加到 UIScrollView 子视图

以编程方式将 UIScrollView 滚动到 Swift 中的子 UIView(子视图)的顶部