Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIStackView inside UIScrollView, grows until maximum height then scrolls

I'm looking to build a view which will grow as subviews are added to it. At first the height will be zero, then should grow as I add subviews until it reaches a maximum size, and then I want it to become scrollable.

If I build this using a UIView inside a UIScrollView and set up the constraints from top to bottom manually, it works as expected. However, I feel like this should be possible using a UIStackView, but when I try either the scroll view doesn't grow, or the contentSize of the scrollView gets stuck at the maximum height, and won't scroll. I've been playing with this for a while and think it might actually be a bug with UIStackView and Autolayout, but hopefully I just missed something. Wrapping the UIStackView in a container UIView doesn't help.

Here's a complete view controller which shows the problem (tapping anywhere adds labels to the scroll view)

import UIKit

class DumbScrollStack: UIViewController {

    let stack = UIStackView()
    let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        //Setup
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(addLabel)))
        stack.axis = .vertical
        view.backgroundColor = .blue
        scrollView.backgroundColor = .red

        //Add scroll view and setup position
        view.addSubview(scrollView)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

        //Set maximum height
        scrollView.heightAnchor.constraint(lessThanOrEqualToConstant: 100).isActive = true

        //add stack
        scrollView.addSubview(stack)
        stack.translatesAutoresizingMaskIntoConstraints = false

        //setup scrollView content size constraints
        stack.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        stack.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
        stack.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
        stack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
        stack.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true

        // Keep short if stack height is lower than scroll height
        // With this constraint the scrollView grows as expected, but doesn't scroll when it goes over 100px
        // Without this constraint the scrollView is always 100px tall but it does scroll
        let constraint = scrollView.heightAnchor.constraint(equalTo: stack.heightAnchor)
        constraint.priority = UILayoutPriority(rawValue: 999)
        constraint.isActive = true

        addLabel()
    }

    @objc func addLabel() {
        let label = UILabel()
        label.backgroundColor = .gray
        label.text = "Hello"
        stack.addArrangedSubview(label)
    }
}
like image 331
Wernzy Avatar asked Jan 22 '19 17:01

Wernzy


People also ask

What is Uistackview?

A streamlined interface for laying out a collection of views in either a column or a row.


2 Answers

Add this

label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000), for: .vertical)

or comment this block

let constraint = scrollView.heightAnchor.constraint(equalTo: stack.heightAnchor)
constraint.priority = UILayoutPriority(rawValue: 999)
constraint.isActive = true

or make this lower than 750 ( the label's default vertical compression )

constraint.priority = UILayoutPriority(rawValue: 749)

the problem is that the label's vertical compression priority is lower than 999 which always make the stack equal to the scrollview height , hence no scroll

like image 83
Sh_Khan Avatar answered Sep 18 '22 20:09

Sh_Khan


Have you looked into using a UICollectionView? It sounds like what you're trying to rebuild.

Make sure to set "Scrolling Enabled" to true and set the scroll direction.

like image 30
Wilson Desimini Avatar answered Sep 18 '22 20:09

Wilson Desimini