【问题标题】:UIScrollView with dynamically sized content具有动态大小内容的 UIScrollView
【发布时间】:2020-05-05 14:59:47
【问题描述】:

(Xcode 11,斯威夫特)

作为 iOS 和 Autolayout 的新手,我正在努力实现一个相当简单的(恕我直言)视图,该视图显示 [垂直] 项目列表。唯一的问题是项目是动态决定的,每个项目都可以是文本或图像(其中任何一个都可能相当大,因此需要滚动)。 WebView 不是一个选项,所以它必须在本地实现。

我是这样理解这个过程的:

  • 在 IB 中创建一个 UIScrollView 并将其调整为外框的大小。
  • 将容器视图创建为 UIScrollView 的子视图(同样,在 IB 中),并将其大小设置为相同。
  • 设置两个宽度相等的约束
  • 在运行时,使用 UILabels/UIImageViews 填充容器视图,并以编程方式设置约束以确保正确的布局。
  • “告诉”滚动视图关于子视图的高度,以使其管理其滚动。

这是正确的方法吗?它似乎对我不起作用(对于一个将非常高的图像动态添加到容器视图的玩具示例 - 我无法让滚动工作)。在上述过程中执行最后一步的正确方法是什么 - 只需将滚动视图的 contentSize 强制为填充容器视图的大小(它似乎对我不起作用)。任何帮助将不胜感激。

【问题讨论】:

    标签: ios swift xcode uiscrollview storyboard


    【解决方案1】:

    在运行时向滚动视图添加多个元素时,您可能会发现使用UIStackView 会更容易...如果设置正确,它会随着每个添加的对象自动增加高度。

    举个简单的例子……

    1) 首先添加一个UIScrollView(我给它一个蓝色背景以便于查看)。将其在所有 4 个方面都约束为零:

    请注意,我们看到“红色圆圈”表示缺少/冲突的约束。暂时忽略它。

    2) 在滚动视图中添加一个UIView 作为“内容视图”(我给它一个systemYellow 背景以便于查看)。在内容布局指南的所有 4 个方面将其限制为零——这将(最终)定义滚动视图的内容大小。还要将其限制为等宽和等高框架布局指南

    重要步骤:选择高度约束,然后在Size Inspector 窗格中选择Placeholder - Remove at build time 复选框。这将在设计时满足 IB 中的自动布局,但将允许该视图的高度根据需要缩小/增长。

    3) 将垂直UIStackView 添加到“内容视图”。将其在所有 4 个面上都约束为零。将其属性配置为Fill / Fill / 8(如下图):

    4) 在视图控制器类的堆栈视图中添加一个@IBOutlet 连接。现在,在运行时,当您将 UI 元素添加到堆栈视图时,您的所有“可滚动性”都将由自动布局处理。

    这是一个示例类:

    class DynaScrollViewController: UIViewController {
    
        @IBOutlet var theStackView: UIStackView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // local var so we can reuse it
            var theLabel = UILabel()
            var theImageView = UIImageView()
    
            // create a new label
            theLabel = UILabel()
            // this gets set to false when the label is added to a stack view,
            // but good to get in the habit of setting it
            theLabel.translatesAutoresizingMaskIntoConstraints = false
            // multi-line
            theLabel.numberOfLines = 0
            // cyan background to make it easy to see
            theLabel.backgroundColor = .cyan
            // add 9 lines of text to the label
            theLabel.text = (1...9).map({ "Line \($0)" }).joined(separator: "\n")
    
            // add it to the stack view
            theStackView.addArrangedSubview(theLabel)
    
            // add another label
            theLabel = UILabel()
            // multi-line
            theLabel.numberOfLines = 0
            // yellow background to make it easy to see
            theLabel.backgroundColor = .yellow
            // add 5 lines of text to the label
            theLabel.text = (1...5).map({ "Line \($0)" }).joined(separator: "\n")
    
            // add it to the stack view
            theStackView.addArrangedSubview(theLabel)
    
            // create a new UIImageView
            theImageView = UIImageView()
            // this gets set to false when the label is added to a stack view,
            // but good to get in the habit of setting it
            theImageView.translatesAutoresizingMaskIntoConstraints = false
            // load an image for it - I have one named background
            if let img = UIImage(named: "background") {
                theImageView.image = img
            }
            // let's give the image view a 4:3 width:height ratio
            theImageView.widthAnchor.constraint(equalTo: theImageView.heightAnchor, multiplier: 4.0/3.0).isActive = true
    
            // add it to the stack view
            theStackView.addArrangedSubview(theImageView)
    
            // add another label
            theLabel = UILabel()
            // multi-line
            theLabel.numberOfLines = 0
            // yellow background to make it easy to see
            theLabel.backgroundColor = .green
            // add 2 lines of text to the label
            theLabel.text = (1...2).map({ "Line \($0)" }).joined(separator: "\n")
    
            // add it to the stack view
            theStackView.addArrangedSubview(theLabel)
    
            // add another UIImageView
            theImageView = UIImageView()
            // this gets set to false when the label is added to a stack view,
            // but good to get in the habit of setting it
            theImageView.translatesAutoresizingMaskIntoConstraints = false
            // load a different image for it - I have one named AquariumBG
            if let img = UIImage(named: "AquariumBG") {
                theImageView.image = img
            }
            // let's give this image view a 1:1 width:height ratio
            theImageView.heightAnchor.constraint(equalTo: theImageView.widthAnchor, multiplier: 1.0).isActive = true
    
            // add it to the stack view
            theStackView.addArrangedSubview(theImageView)
    
        }
    
    }
    

    如果已遵循这些步骤,您应该会得到以下输出:

    并且,在滚动到底部之后:

    【讨论】:

      【解决方案2】:

      对齐约束(前导/尾随/顶部/底部)

      滚动视图和内容视图之间的对齐约束定义了scrollable range of the content例如

      • 如果scrollView.bottom = contentView.bottom,则表示Scroll View是 可滚动到内容视图的底部。
      • 如果 scrollView.bottom = contentView.bottom + 100,则可滚动 Scroll View 的底端将超过 Content View 的端 100 分。
      • 如果scrollView.bottom = contentView.bottom — 100,则底部 即使滚动视图滚动到内容视图也不会到达 底端。

      即Scroll View上的(底部)anchor表示外框的(底部)边缘,即Content View的可见部分; Content View 上的(底部)锚点是指实际内容的边缘,如果不滚动到该边缘,它将被隐藏。 与普通用例不同,Scroll View 和 Content View 之间的对齐约束与 Content View 的实际大小无关。它们只影响“内容视图的可滚动范围”,而不影响“实际内容大小”。 Content View 的实际大小必须另外定义。

      尺寸限制(宽度/高度)

      要实际调整 Content View 的大小,我们可以将 Content View 的大小设置为特定的长度,比如宽/高为 500。如果宽/高超过了 Scroll View 的宽/高,就会有一个滚动条供用户使用滚动。 但是,更常见的情况是,我们希望 Content View 与 Scroll View 具有相同的宽度(或高度)。在这种情况下,我们将有

      contentView.width = scrollView.width

      Content View 的宽度是指内容的实际全宽。另一方面,Scroll View 的宽度是指 Scroll View 的外部容器框架宽度。当然,不一定要等宽,也可以是a * scrollView.width + b等其他形式。 如果我们的 Content View 比 Scroll View 更高(或更宽),就会出现一个滚动条。 内容视图不仅可以是单个视图,还可以是多个视图,只要它们使用 Scroll View 的对齐和大小约束进行适当的约束即可。

      详情可以关注这篇文章:Link

      【讨论】:

        猜你喜欢
        • 2014-05-18
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 1970-01-01
        • 2012-02-17
        • 2015-05-07
        相关资源
        最近更新 更多