I have been messing with this code for a while. My UIViews are not showing up after looping through. I have tried this with out constraints, and the result was each of the UIViews were being rendered on top of each other. I would prefer to use the constraints, like I have it set up.
Can you take a look at this code and explain why my UIViews are not rendering and why my UIScrollViews are not scrolling?
import UIKit
class EventsListViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scrollView = UIScrollView()
let scrollViewConstraints: [NSLayoutConstraint] = [
scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor)
]
self.view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(scrollViewConstraints)
scrollView.backgroundColor = .gray
let stackView = UIStackView(frame: scrollView.frame)
let stackViewConstraints: [NSLayoutConstraint] = [
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)
]
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(stackViewConstraints)
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
stackView.contentMode = .top
stackView.spacing = 5
for event in location.myEvents! {
let listItem = UIView()
listItem.layer.name = event.eventID
listItem.backgroundColor = .blue
stackView.addArrangedSubview(listItem)
let listItemConstraints: [NSLayoutConstraint] = [
listItem.heightAnchor.constraint(equalToConstant: 35),
listItem.widthAnchor.constraint(equalToConstant: stackView.frame.width)
]
listItem.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(listItemConstraints)
}
// scrollView.contentSize = CGSize(width: Int(view.frame.width), height: (height + spacing * count))
}
}
I have tried the following:
- Without constraints results – all UIViews on top of each other
- With constraints results – UIViews not rendering
2
Answers
Autolayout with ScrollView is a bit tricky. As I see, you’re missing a widthAnchor for stackView. Try debugging, you can easily see that your stackView has zero width, so, add this line:
The big issue I see is that you constrain the stack view to the exact size of the scroll view.
UIScrollView
has aframeLayoutGuide
and acontentLayoutGuide
. The stack view should be constrained to thecontentLayoutGuide
. This will allow the stack view to be sized properly based on the views you put in it and it sets thecontentSize
of the scroll view as needed. And it will also allow the stack view to scroll within the scroll view if large enough.Here is a cleaned up version of your code with a bunch of comments. For testing purposes I simply hardcoded the creation of 20 views since I don’t have your data model.
Note the change in
distribution
for the stack view. UsingequalSpacing
allows each view to have its own height. The height of the stack view will be made as tall as need to account for the total height of all view and the spacing. Usingfill
(as you had it) attempts to resize the height of the views to fill the height of the stack view. But you want the views to dictate the height of the stack view, not the other way around.Note that I remove the width constraint on each view. The stack view will take care of the width due to the
alignment
offill
.Also note the use of the
frameLayoutGuide
andcontentLayoutGuide
.Lastly, the last constraint sets the width of the stack view. This is needed since the views in the stack view do not give the stack view an intrinsic width in this case.