Search code examples
swiftuiscrollviewnslayoutanchor

Setting subviews layout anchors to UIScrollView


When i want to set top anchors of my subviews in a UIScrollView, i have to give them a constant height, otherwise scrollView won't scroll. But As they grow in number, it feels like a mess.

For example, if i set my 2nd subviews' topAnchor to first one's bottomAnchor, it won't scroll. I have to set them to scrollView's anchor. Is there a better way to achieve this without giving a constant and calculating the distance myself?

Here is my scrollView:

    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: 500)
    scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    scrollView.isScrollEnabled = true

    belowContainer.addSubview(scrollView)

    scrollView.topAnchor.constraint(equalTo: belowContainer.topAnchor, constant: 20).isActive = true
    scrollView.leadingAnchor.constraint(equalTo: belowContainer.leadingAnchor).isActive = true
    scrollView.trailingAnchor.constraint(equalTo: belowContainer.trailingAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: belowContainer.bottomAnchor, constant: 0).isActive = true

And i use the following variables to get the vertical spacing right, between the subViews

    var counter : CGFloat = 0; // height space counter between uiItems below!
    let multiplierHeight : CGFloat = 32 // we multiply our counter by this value to get the right spacing!

And finally i got my subviews anchoring in a for-loop like this:

    for lbl in labelsArray {
        lbl.font = UIFont(name: fontName, size: 20)

        lbl.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: counter * multiplierHeight).isActive = true          
        lbl.heightAnchor.constraint(equalToConstant: 25).isActive = true
        counter += 1
    }

Solution

  • This doesn’t appear to be the right solution to your problem. Rather, you should cascade the labels such that one label’s bottom constraint is linked to the next label’s top constraint. This way, you won't have to do the top constraint constant multiplication.

    You might, however, want to consider using a stack view to achieve your goal. Pin the stack view to the scroll view’s content view using constraints, and then use your for loop to add the labels to the stack view:

    stackView.addArrangedSubview(lbl)
    

    The stack view has the advantage that you won't need a single layout constraint. Rather, the stack view itself is responsible for positioning its subviews.