具有动态大小内容的 UIScrollView

Ale*_*off 4 xcode storyboard uiscrollview ios swift

(Xcode 11,斯威夫特)

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

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

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

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

Don*_*Mag 8

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

作为一个简单的例子...

1)首先添加一个UIScrollView(我给它一个蓝色背景,使其更容易看到)。在所有 4 个方面将其限制为零:

在此处输入图片说明

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

2)UIView在滚动视图中添加一个“内容视图”(我给了它一个systemYellow背景,以便于查看)。内容布局指南的所有 4 边将其限制为零——这将(最终)定义滚动视图的内容大小。还将其约束为与Frame Layout Guide等宽和等高:

在此处输入图片说明

重要步骤:选择高度约束,然后在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)

    }

}
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

并且,在滚动到底部后:

在此处输入图片说明