1

I have a contentview inside a scrollview along with some other views, and scrollview height will change based on contentview height, and the height of the contentview is decided by the height of its subviews.

I am adding two subviews to contentview programmatically.

childView1 = CustomView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 200))

childView2 = CustomView(frame: CGRect(x: 0, y: 210, width: self.view.frame.width, height: 200))

contentView.addSubview(childView1)
contentView.addSubview(childView2)

// childView1 top should be equal to contentView top           
let topConstraint = NSLayoutConstraint(item: childView1, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 0)

// childView2 bottom should be equal to contentView bottom                       
let bottomConstraint = NSLayoutConstraint(item: childView2, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: 0)

// childView1 leading should be equal to contentView leading 

let leadingConstraint1 = NSLayoutConstraint(item: childView1, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 0)

// childView1 trailing should be equal to contentView trailing  

let trailingConstraint1 = NSLayoutConstraint(item: contentView1, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 0)

// childView2 leading should be equal to contentView leading                       

let leadingConstraint2 = NSLayoutConstraint(item: childView2, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 0)

// childView2 trailing should be equal to contentView trailing  

let trailingConstraint2 = NSLayoutConstraint(item: childView2, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 0)

// Vertical Space between two child views is 10             
let constraintTwoSubViews = NSLayoutConstraint(item: childView1, attribute: .bottom, relatedBy: .equal, toItem: childView2, attribute: .top, multiplier: 1, constant: 10)


contentView.addConstraints([topConstraint , bottomConstraint , leadingConstraint1,trailingConstraint1 , leadingConstraint2 , trailingConstraint2 , constraintTwoSubViews])

The problem is that the contentView height is not growing as per the subviews. Because of that my scroll views is not growing.

  1. When I am adding second child view, I do not want to specify y = 210 , I want its position to be calculated by space constraint between two child views, Is it possible?

  2. How can I make content view height grow as per its subviews?

1
  • make sure to set translatesAutoresizingMaskIntoConstraints to false for both childView1 and childView2 like: childView1.translatesAutoresizingMaskIntoConstraints = false Commented Jan 16, 2018 at 10:53

1 Answer 1

1

What I do when I need a scrollable view:

  1. I add a scrollView to the hierarchy and use autolayout to properly layout it, e.g., if it is supposed to cover the whole view of the viewController:

    scrollView.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        scrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
        scrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
        scrollView.topAnchor.constraint(equalTo: self.view.topAnchor),
        scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
    ])
    
  2. Then you need to add a contentView to the scrollView and provide a proper layout constraints for it, so if you want vertically scrollable scrollView in the example I started above, you need following autolayout constraints:

    contentView.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        // horizontal anchors of contentView are constrained to scrollView superview
        // to prevent it from scrolling horizontally
        contentView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
        contentView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
        // but vertical anchors of contentView are constrained to
        // scrollView to allow scrolling
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
    ])
    

    Notice here that I constrained the leftAnchor and rightAnchor of the contentView to the self.view rather than to scrollView to make it of fixed width. However, top and bottom anchors are constrained to the scrollView, so they are expanded and scrollable when contentView needs more space.

  3. Now you add to the contentView all the content that you want, and you lay it out using autolayout as if the contentView was a view with infinite height - scrollView will take care of presenting it whole by scrolling. In your case I think you can use UIStackView to lay out those two views. However, CustomView's frames will be calculated using autolayout, so I don't think you can rely on setting the frames directly - therefore I use constraints to set their heights too (widths will be stretched by the stackView):

    let stack = UIStackView()
    stack.spacing = 10
    stack.distribution = .fill
    stack.alignment = .fill
    stack.axis = .vertical
    
    contentView.addSubview(stack)
    stack.addArrangedSubview(childView1)
    stack.addArrangedSubview(childView2)
    
    childView1.translatesAutoresizingMasks = false
    childView2.translatesAutoresizingMasks = false
    
    NSLayoutConstraint.activate([
        contentView.topAnchor.constraint(equalTo: stack.topAnchor),
        contentView.leadingAnchor.constraint(equalTo: stack.leadingAnchor),
        contentView.trailingAnchor.constraint(equalTo: stack.trailingAnchor),
        contentView.bottomAnchor.constraint(equalTo: stack.bottomAnchor),
    
        // setting their heights using constraints
        childView1.heightAnchor.constraint(equalToConstant: 200),
        childView2.heightAnchor.constraint(equalToConstant: 200),
        ])
    
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.