sakoaskoaso
sakoaskoaso

Reputation: 347

Swift how to set UIView's height constraint based on it's content

I have a UIView in my swift code

let profile_inf_wrapper: UIView = {
        let v = UIView()
        v.backgroundColor = .red
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    profile_inf_wrapper.topAnchor.constraint(equalTo: view.topAnchor, constant:64).isActive = true
    profile_inf_wrapper.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    profile_inf_wrapper.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    profile_inf_wrapper.heightAnchor.constraint(equalToConstant:  view.frame.height/4).isActive = true

    backgroundImageView.topAnchor.constraint(equalTo: profile_inf_wrapper.topAnchor).isActive = true
    backgroundImageView.leftAnchor.constraint(equalTo: profile_inf_wrapper.leftAnchor).isActive = true
    backgroundImageView.rightAnchor.constraint(equalTo: profile_inf_wrapper.rightAnchor).isActive = true
    backgroundImageView.bottomAnchor.constraint(equalTo: profile_inf_wrapper.bottomAnchor).isActive = true

    profileImage.centerYAnchor.constraint(equalTo: profile_inf_wrapper.centerYAnchor).isActive = true
    profileImage.leftAnchor.constraint(equalTo: view.leftAnchor, constant:25).isActive = true
    profileImage.widthAnchor.constraint(equalToConstant: 110).isActive  = true
    profileImage.heightAnchor.constraint(equalToConstant: 110).isActive = true

    usernameLabel.topAnchor.constraint(equalTo: profile_inf_wrapper.topAnchor, constant:40).isActive = true
    usernameLabel.leftAnchor.constraint(equalTo: profileImage.rightAnchor, constant:20).isActive = true

    countryIcon.topAnchor.constraint(equalTo: usernameLabel.bottomAnchor, constant:10).isActive = true
    countryIcon.leftAnchor.constraint(equalTo: profileImage.rightAnchor, constant:20).isActive = true
    countryIcon.widthAnchor.constraint(equalToConstant: 25).isActive = true
    countryIcon.heightAnchor.constraint(equalToConstant: 25 ).isActive = true

    countryName.topAnchor.constraint(equalTo: usernameLabel.bottomAnchor, constant:5).isActive = true
    countryName.leftAnchor.constraint(equalTo: countryIcon.rightAnchor, constant:10).isActive = true
    countryName.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

All these elements are the subviews of profile_inf_wrapper.Sometimes view.frame.height/4 is too small and i want to be able to resize the UIView based on it's content

Upvotes: 2

Views: 7064

Answers (3)

Jaydeep Vyas
Jaydeep Vyas

Reputation: 4470

For setting the height of uiview dynamically you have to add height/bottom constraint to the view in your problem it might be

profile_inf_wrapper.heightAnchor.constraint(equalToConstant: view.frame.height/4+countryName.frame.size.height).isActive = true

you also need the view size to fit to get actual updated size like

countryName.sizeToFit() 

And then update layout if needed to get all affect

Upvotes: 0

EmilioPelaez
EmilioPelaez

Reputation: 19874

There's a property in UIView called intrinsicContentSize. It returns the smallest size that the view would need show all of it's content.

While the default implementation is not very useful because a UIView doesn't have any content on it's own, all of the default subclasses implement it.

A UILabel will return a size that fits the text perfectly, and a UIButton will return a size that fits it's contents plus whatever spacing you've added. You get the gist of it.

You can take advantage of this property by only constraining either width or height of a view, not both. If you constrain the width of a UILabel and add more text, it will grow vertically.

Finally, when you add subviews to a UIView, and you add constraints to both margins of an axis (top and bottom or left and right), as long as there's a "chain" of constraints and views, and the view doesn't have any constraints on the size, it will expand to fit.

For example, if you have a view with a label and a button, vertically arranged, if the label is constrained to the top, then constrained to the button, and the button is constrained to the bottom, as long as the container view doesn't have a height constraint, it will expand to fit the two views plus the margins perfectly.

Your goal should always be to use the least amount of constraints to express your design, without removing useful constraints. Make sure you take advantage of the intrinsicContentSize.

Upvotes: 1

Chayce Heiberg
Chayce Heiberg

Reputation: 7

The first thing you want to do is make a reference to the height constraint of profile_inf_wrapper.

var profile_inf_wrapper_height_constraint: NSLayoutConstraint?

I don't know the details of your content, but when the view needs resized, you can check that with a conditional in your viewController,

if contentRequiresResizing {
    profile_inf_wrapper_height_constraint.constant = view.frame.width/3
else {
    profile_inf_wrapper_height_constraint.constant = view.frame.width/4
}

By referencing constraints, it allows you to support dynamic UI changes easily.

As a side note, I would recommend renaming your UIView variable name so that the reference constraint isn't so long. The Swift 3 API guidelines also support lowerCamelCase, as opposed to underscore naming.

Upvotes: 0

Related Questions