I have a UIStackView
.
I have added some views.
The last view should be at to the bottom of the screen. To achieve this I have added a view that acts as a spacer, I have set a height on the first and last view with the idea that the middle view stretches to fill the space.
This works.
let topView = UIView(frame: .zero)
topView.withSize(.init(width: 0, height: 100))
topView.backgroundColor = .lightGray
let spacerView = UIView(frame: .zero)
spacerView.backgroundColor = .darkGray
let bottomView = UIView(frame: .zero)
bottomView.withSize(.init(width: 0, height: 200))
bottomView.backgroundColor = .lightGray
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 0
stackView.distribution = .fill
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
[topView, spacerView, bottomView].forEach { stackView.addArrangedSubview($0) }
I have a scenario however where the screen size may be smaller than the size of the views.
I am trying to embed my UIStackView
in a UIScrollView
however when I do this, the spacer view no longer stretches itself. It is as if the height is now zero. (I have added spacing to show the top and bottom views)
let topView = UIView(frame: .zero)
topView.withSize(.init(width: 0, height: 100))
topView.backgroundColor = .lightGray
let spacerView = UIView(frame: .zero)
spacerView.backgroundColor = .darkGray
let bottomView = UIView(frame: .zero)
bottomView.withSize(.init(width: 0, height: 200))
bottomView.backgroundColor = .lightGray
let scrollView = UIScrollView(frame: .zero)
addSubviews(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 8
stackView.distribution = .fill
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// Attaching the content's edges to the scroll view's edges
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
// Satisfying size constraints
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
[topView, spacerView, bottomView].forEach { stackView.addArrangedSubview($0) }
I would expect in this case my UIStackView
to still fill the view and only be scrollable if a child view causes it to grow in height beyond the visible bounds of the view.
Use a UITableView with a UICollectionView as a Footer.
You can find a tutorial here: https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/
This is for adding a collectionView as a header but works the same for footer.
private let tableView: UITableView = {
let view = UITableView(frame: .zero, style: .plain)
view.translatesAutoresizingMaskIntoConstraints = false
view.estimatedRowHeight = 44
view.rowHeight = UITableView.automaticDimension
view.keyboardDismissMode = .interactive
view.tableFooterView = //Your Custom View with CollectionView here
return view
}()