编程 auto-layout 不计算 UIScrollView 的高度
Programmatic auto-layout not calculating height of UIScrollView
我有一个 UIViewController
,其中有一个 header 区域。 header 元素的底部是一行 UI 按钮。在这些按钮下方,我放置了一个 UIScrollView
,其中嵌入了一个名为 contentContainer
的 UIView
。在该容器内有许多 UILabels
和 UIViews
样式作为分隔符。
整个 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
我有一个 UIViewController
,其中有一个 header 区域。 header 元素的底部是一行 UI 按钮。在这些按钮下方,我放置了一个 UIScrollView
,其中嵌入了一个名为 contentContainer
的 UIView
。在该容器内有许多 UILabels
和 UIViews
样式作为分隔符。
整个 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