1

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.

PJR
  • 13,052
  • 13
  • 64
  • 104

1 Answers1

5

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:

enter image description here

joern
  • 27,354
  • 7
  • 90
  • 105
  • thanks for your answer, I added view because I have some other labels in my view – PJR Sep 16 '18 at 12:01
  • That does not change much. I updated my answer to include the `UIView` – joern Sep 16 '18 at 12:12
  • @Thanks joerm again. So my question is I need to do both ? code and through storybaord ? becuase I set from stroyboard it sohws me conflicts error for y postion or height of scrollview – PJR Sep 16 '18 at 12:19
  • My example is code only. No Storyboard involved. Check my updated answer for an example that uses ONLY a Storyboard. – joern Sep 16 '18 at 12:29
  • @PJR "conflicts error for y postion or height of scrollview" in storyboard could be resolved by adding one or more fixed height items to the stackviews (or setting a minimum height constraint) – 9dan Sep 16 '18 at 12:41
  • @9dan, but in that case my stackview will be limited to fixed height, I guess – PJR Sep 16 '18 at 12:45
  • @PJR You don't have to set a fixed height to your `UIStackViews`. Just make sure that the views that you add to the StackViews have their heights defined. Many UIView subclasses (like `UILabel` and `UIButton`) have an `instrinsicContentSize` that defines their height depending on the content. A pure UIView with nothing in it (like in my example) needs to have a `height` constraint to define the height. That's why my example depends on the height constraints. Normally you would not have to add those, because the `UIViews` would have content that defines the height of the `UIView` – joern Sep 16 '18 at 12:52
  • @joern, It worked. Thanks for your time. I was very active on stack before some years. I know how much efforts you did for my issue. Thanks a lot gain. – PJR Sep 16 '18 at 13:16