Problem:
I want my footer UIStackView
to hug its content when views are laid out, and take priority over the UIScrollView
. Currently the header UIStackView
and main body UIScrollView
hug its contents, causing the footer UIStackView
to expand, therefore leaving a lot of space below its contents and not looking like it’s not pinned to the bottom. I would like the header(UIStackView) and footer(UIStackView) to hug its contents, and the main body(UIScrollView) to expand as needed.
Platform specs:
- iOS 15
- Xcode 13.1
Context:
I have a UIViewController
with the following view hierarchy
UIViewController
-UIView
-UIStackView(header)
-ScrollView(scrollable main body)
-UIView
-UIStackView
-UIStackView(footer)
Requirements for header and footer:
- stay on screen all the time
Constraints:
self.view.addSubview(self.headerStackView)
NSLayoutConstraint.activate([
self.headerStackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
self.headerStackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
self.headerStackView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor)
])
self.view.addSubview(self.scrollView)
NSLayoutConstraint.activate([
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
self.scrollView.topAnchor.constraint(equalTo: self.headerStackView.bottomAnchor)
])
self.view.addSubview(self.footerStackView)
NSLayoutConstraint.activate([
self.footerStackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
self.footerStackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
self.footerStackView.topAnchor.constraint(equalTo: self.scrollView.bottomAnchor),
self.footerStackView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor)
])
2
Answers
It turns out thew view within the footer stackview was not constrained properly. Adding the missing constraint fixed the issue.
You can do this by constraining the Top of the footer view to the Bottom of the scroll view’s content, but with
.priority = .defaultLow
, then constrain the Bottom of the footer view to less-than-or-equal-to the Bottom of the scroll view’s frame.Here’s how it can look…
view
scrollView
A quick example:
and it will look like this when running:
As we add content (in this case, just adding more lines to a label), it will "push down" the footer view until it hits the bottom of the scroll view’s frame… at which point we can scroll behind the footer view.