I have a stackView inside a scrollView and I would like to pin the stackView such that it starts from the bottom and grows going up as more views are added to it.
Image showing current behaviour showing the stackView pinned to the top of the view and the content going from top t bottom.
Image showing desired behaviour, showing stack view growing from bottom to top.
Current code:
CustomStackView
open class CustomStackView: UIView {
public var scrollView: UIScrollView = {
let view = UIScrollView(frame: .zero)
view.isScrollEnabled = true
view.bounces = true
view.alwaysBounceVertical = true
view.keyboardDismissMode = .interactive
view.layoutMargins = .zero
view.clipsToBounds = false
return view
}()
public var stackView: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fillProportionally
let gap: CGFloat = 0
stackView.spacing = gap
stackView.layoutMargins = UIEdgeInsets(top: gap, left: gap, bottom: gap, right: gap)
stackView.isLayoutMarginsRelativeArrangement = true
return stackView
}()
override public init(frame: CGRect) {
super.init(frame: frame)
self.layoutMargins = .zero
backgroundColor = .green
scrollView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(scrollView)
NSLayoutConstraint.activate([scrollView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor)])
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(lessThanOrEqualTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)])
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
CellView
class CellView: UIView {
private let title: UILabel = {
let label = UILabel(frame: .zero)
label.textColor = .black
label.font = .systemFont(ofSize: 18, weight: .medium)
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .left
label.text = "Title"
return label
}()
private let subTitle: UILabel = {
let label = UILabel(frame: .zero)
label.textColor = .lightGray
label.font = .systemFont(ofSize: 14, weight: .regular)
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "subTitle"
label.isHidden = true
return label
}()
private let seperatorView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .lightGray
view.heightAnchor.constraint(equalToConstant: 0.5).isActive = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let headerStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .leading
stackView.distribution = .fill
stackView.spacing = 0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(frame: CGRect) {
super.init(frame: .zero)
setupView()
}
init(title: String) {
super.init(frame: .zero)
setupView()
configureView(with: title)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupView() {
self.backgroundColor = .gray
headerStackView.addArrangedSubview(title)
headerStackView.addArrangedSubview(subTitle)
addSubview(seperatorView)
addSubview(headerStackView)
setupConstraints()
}
private func setupConstraints() {
self.heightAnchor.constraint(equalToConstant: 50).isActive = true
headerStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 16).isActive = true
headerStackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
headerStackView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
seperatorView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
seperatorView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
seperatorView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
}
private func configureView(with title: String) {
self.title.text = title
}
}
ViewController:
class TestViewController: UIViewController {
private let containerView: UIView = {
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.red
view.clipsToBounds = true
return view
}()
private let customStackView: CustomStackView = {
let view = CustomStackView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
configureView()
}
func setupView() {
view.addSubview(containerView)
containerView.clipsToBounds = true
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40),
containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
containerView.addSubview(customStackView)
NSLayoutConstraint.activate([
customStackView.topAnchor.constraint(equalTo: containerView.topAnchor),
customStackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
customStackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
customStackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
])
}
func configureView() {
customStackView.stackView.addArrangedSubview(CellView(title: "Title"))
customStackView.stackView.addArrangedSubview(CellView(title: "Tesla"))
customStackView.stackView.addArrangedSubview(CellView(title: "Lucid"))
customStackView.stackView.addArrangedSubview(CellView(title: "Merc"))
customStackView.stackView.addArrangedSubview(CellView(title: "BMW"))
}
}
I would like the view to behave in this way when it reaches the top: