0

So I have a scrollView, inside that scrollView is a stackView that contains every views in the screen.

The problem is my stackView has many hide-able views so I need to adjust my containsVieww's height base on my stackView's height

my psuedo code should be like this :


 override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    print(stackView.bounds.height)
    // do logic to change contentView size here
 }
func setupView(){
    scrollView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
    scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    scrollView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
    scrollView.backgroundColor = .white
    scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height)
    
    scrollView.addSubview(stackView)
    stackView.setArrangedSubView(views: [label1, label 2, label 3, label 4, ..., label n]
    [label1, label 2, label 3].isHidden = true
}

func onHitButton(){
   if isHidden {
   [label1, label 2, label 3].isHidden = false
   isHidden = false
  } else {
   [label1, label 2, label 3].isHidden = true
   isHidden = true
  }
  print(stackView.bounds.height) // still return the ex height
}

Here is the problem:

On first init, my [label1,2,3].isHidden = true, my stackViewHeight is 500

When my onHitButton is called, my [label1,2,3].isHidden = false, my stackViewHeight is still 500 but the screen displays correctly, those labels are visible now and my stackView is stretched. And of course my scrollView is not displays correctly.

Then I hit my onHitButton again, those labels are hidden, my stackView is shrink on screen but the stackViewHeight returned 850?

It's supposed to be the other way around.

I also tried to print the height on another button call and it return the right height? Seem like viewDidLayoutSubviews called too early.

To sum it up: stackView return the height before it resize it self

bao le
  • 927
  • 2
  • 7
  • 12

1 Answers1

1

Use auto-layout to constrain the stack view to the scroll view's Content Layout Guide:

    scrollView.addSubview(stackView)
    
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    // reference to scrollView's Content Layout Guide
    let cGuide = scrollView.contentLayoutGuide

    // reference to scrollView's Frame Layout Guide
    let fGuide = scrollView.frameLayoutGuide
    
    NSLayoutConstraint.activate([
        
        // constrain stackView to scrollView's Content Layout Guide
        stackView.topAnchor.constraint(equalTo: cGuide.topAnchor),
        stackView.leadingAnchor.constraint(equalTo: cGuide.leadingAnchor),
        stackView.trailingAnchor.constraint(equalTo: cGuide.trailingAnchor),
        stackView.bottomAnchor.constraint(equalTo: cGuide.bottomAnchor),
        
        // constrain stackView's Width to scrollView's Frame Layout Guide
        stackView.widthAnchor.constraint(equalTo: fGuide.widthAnchor),
        
    ])
    

This will completely avoid the need to ever set .contentSize -- it will all be handled by auto-layout.

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • why would you give leading and trailing anchor why there is already a widthAnchor? Beside that one, everything works perfectly. Thanks – bao le Oct 08 '21 at 03:26
  • One more minor problem that I found is it seems like I can't adjust bottomAnchor constant, the bottom of my last view in stackView is alway at view.BottomAnchor without any space. I tried to give constant in both stackView bottomAnchor and scrollView bottomAnchor but it didn't work . But giving `topAnchor constant` work. Strange – bao le Oct 08 '21 at 04:16
  • *Leading / Trailing / Width Anchors* ... that's the way scroll views work. Leading and Trailing + Width determines the **Horizontal** scrolling size, Top and Bottom + Height determines the **Vertical** scrolling size. Here, we use the stack view content (the arranged subviews) to determine its height. Comment-out the Width constraint line, and see what you get. Then try setting the Constant on the Width constraint to 100, or 500, or 1000 and see what you get. – DonMag Oct 08 '21 at 12:38
  • *"my last view in stackView is alway at view.BottomAnchor without any space"* ... Do you mean you want some "empty space" after the bottom of the stack view? If so, give a negative value for the bottom anchor's constant. For example: `stackView.bottomAnchor.constraint(equalTo: cGuide.bottomAnchor, constant: -100.0),` – DonMag Oct 08 '21 at 12:41