Reputation: 13180
Here is my view's hierarchy
ScrollView
-> View
-> Stackview1
-> view1
-> view2
.
.
.
-> Stackview1
-> view1
-> view2
.
.
.
So here my stackview's height is generated dynamically as per the views added on .swift file
If I give bottom constraint to the super view it is working only with single stackview but If I use both stackviews it is not considering to the second stackview.
Upvotes: 1
Views: 1800
Reputation: 27620
It's a bit hard to tell what the problem is, because you have not posted your constraints, but the solution is pretty straight forward:
You need the following constraints:
ScrollView:
topAnchor
to view.topAnchor
leadingAnchor
to view.leadingAnchor
trailingAnchor
to view.trailingAnchor
bottomAnchor
to view.bottomAnchor
UIView that wraps the 2 UIStackViews:
topAnchor
to scrollView.topAnchor
leadingAnchor
to scrollView.leadingAnchor
trailingAnchor
to scrollView.trailingAnchor
bottomAnchor
to scrollView.bottomAnchor
Upper StackView:
topAnchor
to wrapperView.topAnchor
leadingAnchor
to wrapperView.leadingAnchor
trailingAnchor
to wrapperView.trailingAnchor
widthAnchor
to scrollView.widthAnchor
(to define the width of the ScrollView's contentSize
)Lower StackView:
topAnchor
to upperStackView.bottomAnchor
leadingAnchor
to wrapperView.leadingAnchor
trailingAnchor
to wrapperView.trailingAnchor
bottomAnchor
to wrapperView.bottomAnchor
Now when you add a UIView
to one of the UIStackViews
the UIScrollView gets updated automatically.
Here is a working example: (I added two UIButtons
to add more UIViews
to both UIStackViews
)
class ViewController: UIViewController {
let upperStackView = UIStackView()
let lowerStackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
let scrollView = UIScrollView()
view.addSubview(scrollView)
scrollView.backgroundColor = .white
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
let wrapperView = UIView()
scrollView.addSubview(wrapperView)
wrapperView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
wrapperView.topAnchor.constraint(equalTo: scrollView.topAnchor),
wrapperView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
wrapperView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
wrapperView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
])
upperStackView.axis = .vertical
upperStackView.distribution = .equalSpacing
upperStackView.alignment = .fill
wrapperView.addSubview(upperStackView)
upperStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
upperStackView.topAnchor.constraint(equalTo: wrapperView.topAnchor),
upperStackView.leadingAnchor.constraint(equalTo: wrapperView.leadingAnchor),
upperStackView.trailingAnchor.constraint(equalTo: wrapperView.trailingAnchor),
upperStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
lowerStackView.axis = .vertical
lowerStackView.distribution = .equalSpacing
lowerStackView.alignment = .fill
wrapperView.addSubview(lowerStackView)
lowerStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
lowerStackView.topAnchor.constraint(equalTo: upperStackView.bottomAnchor),
lowerStackView.leadingAnchor.constraint(equalTo: wrapperView.leadingAnchor),
lowerStackView.trailingAnchor.constraint(equalTo: wrapperView.trailingAnchor),
lowerStackView.bottomAnchor.constraint(equalTo: wrapperView.bottomAnchor)
])
for _ in 0...3 {
addView(to: upperStackView)
addView(to: lowerStackView)
}
let lowerButton = UIButton(type: .system)
lowerButton.setTitle("Add to lower StackView", for: .normal)
lowerButton.backgroundColor = .white
lowerButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(lowerButton)
NSLayoutConstraint.activate([
lowerButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60),
lowerButton.widthAnchor.constraint(equalToConstant: 240),
lowerButton.heightAnchor.constraint(equalToConstant: 44),
lowerButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
lowerButton.addTarget(self, action: #selector(addViewToLowerStackView), for: .touchUpInside)
let upperButton = UIButton(type: .system)
upperButton.setTitle("Add to upper StackView", for: .normal)
upperButton.backgroundColor = .white
upperButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(upperButton)
NSLayoutConstraint.activate([
upperButton.bottomAnchor.constraint(equalTo: lowerButton.topAnchor, constant: -20),
upperButton.widthAnchor.constraint(equalToConstant: 240),
upperButton.heightAnchor.constraint(equalToConstant: 44),
upperButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
upperButton.addTarget(self, action: #selector(addViewToUpperStackView), for: .touchUpInside)
}
func addView(to stackView: UIStackView) {
let view = UIView()
view.backgroundColor = stackView == upperStackView ? .blue : .green
view.alpha = CGFloat(stackView.arrangedSubviews.count + 1) * 0.1
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([view.heightAnchor.constraint(equalToConstant: 120)])
stackView.addArrangedSubview(view)
}
@objc func addViewToUpperStackView() {
addView(to: upperStackView)
}
@objc func addViewToLowerStackView() {
addView(to: lowerStackView)
}
}
UPDATE:
You could also make this work using only a Storyboard:
Upvotes: 5