Ios 编程自动布局不计算UIScrollView的高度
我有一个aIos 编程自动布局不计算UIScrollView的高度,ios,swift,mobile,autolayout,programmatically-created,Ios,Swift,Mobile,Autolayout,Programmatically Created,我有一个aUIViewController,它有一个标题区域。在标题元素的底部是一行UIButtons。在这些按钮下面,我放置了一个UIScrollView,其中嵌入了一个名为contentContainer的UIView。在该容器中有许多ui标签和ui视图样式为分隔符 整个ViewController、所有子视图及其关联的自动布局约束都是以编程方式构造的 除了UIScrollView没有垂直滚动之外,一切似乎都很好。如果我显式地给contentContainer子视图一个带有自动布局高度约束的
UIViewController
,它有一个标题区域。在标题元素的底部是一行UIButtons。在这些按钮下面,我放置了一个UIScrollView
,其中嵌入了一个名为contentContainer
的UIView
。在该容器中有许多ui标签
和ui视图
样式为分隔符
整个ViewController、所有子视图及其关联的自动布局约束都是以编程方式构造的
除了UIScrollView没有垂直滚动之外,一切似乎都很好。如果我显式地给contentContainer
子视图一个带有自动布局高度约束的大小,它就可以工作了
这让我觉得contentContainer的高度并没有被精确计算出来
如何构建每个UI元素的示例:
let divider1: UIView = {
let divider = UIView()
divider.backgroundColor = Colors.white10
divider.translatesAutoresizingMaskIntoConstraints = false
return divider
}()
我的视图加载:
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()
}
我的自动布局约束:
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
}
contentContainer.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
contentContainer.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
}
以及UI的一个快照,其中表的浅灰色部分表示contentContainer
:
感谢您的帮助。为了计算
contentContainer
的高度,自动布局需要从contentContainer
顶部到底部的一系列子视图。在您的例子中,除了您最底部的视图未连接到contentContainer
的底部之外,您似乎拥有该链
添加一个约束,将divider4
的底部连接到contentContainer
的底部。这将允许自动布局计算contentContainer
的大小
此外,不应设置这些约束:
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
}
contentContainer.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
contentContainer.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
谢谢你的提示!我添加了
divider4.bottomAnchor.constraint(equalTo:contentContainer.bottomAnchor,常量:0)。isActive=true
,不幸的是它仍然不起作用。想知道为什么吗?我想你不想要contentContainer.centerYAnchor
和contentContainer.centerXAnchor
约束。试着把这些评论出来。啊,你说得对!非常感谢你的帮助。按照上面的指定,将divider4
bottomAnchor添加到contentContainer
,然后移除centerX和centerY锚解决了这个问题。ScrollView的框架可能小于内容大小,这是一种自然行为,请仔细想想。如果希望帧大小等于contentSize,则应自行设置。如果您想要自动计算高度,您应该创建一个自定义contentView来包装所有子视图以实现这一点。在我正在测试的实例中,内容比UIScrollView
frame要大—我认为contentContainer
是您所指的自定义视图,我希望它能根据自动布局约束进行计算。好的,如果你想要自定义视图,可以自动计算它的高度。有三件事需要确认。1.顶部约束应与顶部子视图的顶部相关。2.底部约束应与底部子视图的底部相关。3.所有子视图约束应明确无误,且高度应可由自动布局系统解决。:)