编程 auto-layout 不计算 UIScrollView 的高度

Programmatic auto-layout not calculating height of UIScrollView

我有一个 UIViewController,其中有一个 header 区域。 header 元素的底部是一行 UI 按钮。在这些按钮下方,我放置了一个 UIScrollView,其中嵌入了一个名为 contentContainerUIView。在该容器内有许多 UILabelsUIViews 样式作为分隔符。

整个 ViewController、所有子视图及其关联的 auto-layout 约束均以编程方式构建。

除了 UIScrollView 不是垂直滚动之外,一切似乎都运行良好。如果我明确地给 contentContainer 子视图一个带有 auto-layout 高度限制的大小,它就可以工作。

这让我认为 contentContainer 的高度计算不准确。

如何构建每个 UI 元素的示例:

let divider1: UIView = {
    let divider = UIView()
    divider.backgroundColor = Colors.white10
    divider.translatesAutoresizingMaskIntoConstraints = false

    return divider
}()

我的 viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.addSubview(buttonClose)
    self.view.addSubview(labelPlaceTitle)
    self.view.addSubview(buttonShare)
    self.view.addSubview(buttonRoute)
    self.view.addSubview(buttonDelete)
    self.view.addSubview(scrollView)

    scrollView.addSubview(contentContainer)

    contentContainer.addSubview(divider1)
    contentContainer.addSubview(labelAddressLabel)
    contentContainer.addSubview(labelAddressActual)
    contentContainer.addSubview(divider2)
    contentContainer.addSubview(labelDateLabel)
    contentContainer.addSubview(labelDateActual)
    contentContainer.addSubview(divider3)
    contentContainer.addSubview(labelNoteLabel)
    contentContainer.addSubview(labelNoteActual)
    contentContainer.addSubview(buttonAddNote)
    contentContainer.addSubview(divider4)

    setupLayout()
}

我的auto-layout约束:

private func setupLayout() {
    buttonClose.topAnchor.constraint(equalTo: view.topAnchor, constant: 16).isActive = true
    buttonClose.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -16).isActive = true
    buttonClose.widthAnchor.constraint(equalToConstant: 28).isActive = true
    buttonClose.heightAnchor.constraint(equalToConstant: 28).isActive = true

    labelPlaceTitle.topAnchor.constraint(equalTo: view.topAnchor, constant: 48).isActive = true
    labelPlaceTitle.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 24).isActive = true
    labelPlaceTitle.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -24).isActive = true

    buttonShare.topAnchor.constraint(equalTo: labelPlaceTitle.bottomAnchor, constant: 16).isActive = true
    buttonShare.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 24).isActive = true
    buttonShare.widthAnchor.constraint(equalToConstant: 48).isActive = true
    buttonShare.heightAnchor.constraint(equalToConstant: 48).isActive = true

    buttonRoute.topAnchor.constraint(equalTo: labelPlaceTitle.bottomAnchor, constant: 16).isActive = true
    buttonRoute.leftAnchor.constraint(equalTo: buttonShare.rightAnchor, constant: 8).isActive = true
    buttonRoute.widthAnchor.constraint(equalToConstant: 48).isActive = true
    buttonRoute.heightAnchor.constraint(equalToConstant: 48).isActive = true

    buttonDelete.topAnchor.constraint(equalTo: labelPlaceTitle.bottomAnchor, constant: 16).isActive = true
    buttonDelete.leftAnchor.constraint(equalTo: buttonRoute.rightAnchor, constant: 8).isActive = true
    buttonDelete.widthAnchor.constraint(equalToConstant: 48).isActive = true
    buttonDelete.heightAnchor.constraint(equalToConstant: 48).isActive = true

    scrollView.topAnchor.constraint(equalTo: buttonRoute.bottomAnchor, constant: 32).isActive = true
    scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
    scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true

    contentContainer.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
    contentContainer.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true
    contentContainer.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
    contentContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true
    contentContainer.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
    contentContainer.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
    contentContainer.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

    divider1.topAnchor.constraint(equalTo: contentContainer.topAnchor, constant: 24).isActive = true
    divider1.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    divider1.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true
    divider1.heightAnchor.constraint(equalToConstant: 1).isActive = true

    labelAddressLabel.topAnchor.constraint(equalTo: divider1.bottomAnchor, constant: 12).isActive = true
    labelAddressLabel.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelAddressLabel.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    labelAddressActual.topAnchor.constraint(equalTo: labelAddressLabel.bottomAnchor, constant: 4).isActive = true
    labelAddressActual.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelAddressActual.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    divider2.topAnchor.constraint(equalTo: labelAddressActual.bottomAnchor, constant: 12).isActive = true
    divider2.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    divider2.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true
    divider2.heightAnchor.constraint(equalToConstant: 1).isActive = true

    labelDateLabel.topAnchor.constraint(equalTo: divider2.bottomAnchor, constant: 12).isActive = true
    labelDateLabel.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelDateLabel.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    labelDateActual.topAnchor.constraint(equalTo: labelDateLabel.bottomAnchor, constant: 4).isActive = true
    labelDateActual.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelDateActual.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    divider3.topAnchor.constraint(equalTo: labelDateActual.bottomAnchor, constant: 12).isActive = true
    divider3.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    divider3.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true
    divider3.heightAnchor.constraint(equalToConstant: 1).isActive = true

    labelNoteLabel.topAnchor.constraint(equalTo: divider3.bottomAnchor, constant: 12).isActive = true
    labelNoteLabel.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelNoteLabel.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    labelNoteActual.topAnchor.constraint(equalTo: labelNoteLabel.bottomAnchor, constant: 4).isActive = true
    labelNoteActual.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    labelNoteActual.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true

    buttonAddNote.topAnchor.constraint(equalTo: labelNoteActual.bottomAnchor, constant: 12).isActive = true
    buttonAddNote.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    buttonAddNote.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true
    buttonAddNote.heightAnchor.constraint(equalToConstant: 32).isActive = true

    divider4.topAnchor.constraint(equalTo: buttonAddNote.bottomAnchor, constant: 12).isActive = true
    divider4.leftAnchor.constraint(equalTo: contentContainer.leftAnchor, constant: 24).isActive = true
    divider4.rightAnchor.constraint(equalTo: contentContainer.rightAnchor, constant: -24).isActive = true
    divider4.heightAnchor.constraint(equalToConstant: 1).isActive = true
}

}

还有 UI 的镜头,sheet 的浅灰色部分代表 contentContainer

Screenshot of UI

感谢您的帮助。

为了计算 contentContainer 的高度,Auto Layout 需要一个从 contentContainer 的顶部到底部的完整的子视图链。在您的情况下,您似乎拥有该链条,只是您的最底部视图未连接到 contentContainer.

的底部

添加连接 divider4 底部和 contentContainer 底部的约束。这将允许 Auto Layout 计算 contentContainer.

的大小

此外,您不应设置这些限制条件:

contentContainer.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
contentContainer.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true