I have a a UIViewController
which has a header area. At the bottom of that header element is a row of UIButtons. Below these buttons, I've placed a UIScrollView
, within which is embedded a UIView
called contentContainer
. Within that container is a number of UILabels
and UIViews
styled as dividers.
The entire ViewController, all subviews, and their associated auto-layout constraints are constructed programmatically.
Everything seems to work well, with the exception that the UIScrollView is not vertically scrolling. If I explicitly give the contentContainer
subview a size with an auto-layout height constraint, it works.
This leads me to think that height of the contentContainer is not being accurately computed.
Example of how each UI element is built:
let divider1: UIView = {
let divider = UIView()
divider.backgroundColor = Colors.white10
divider.translatesAutoresizingMaskIntoConstraints = false
return divider
}()
My 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()
}
My auto-layout constraints:
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
}
}
And a shot of the UI, with the light grey portion of the sheet representing the contentContainer
:
Thanks for your help.