Search code examples
swiftautolayout

Unable to properly arrange two UILabels in a Stackview in Swift programatically


This is the hierarchy I have:

  1. Vertical Stackview that will contain the rows (mystack)
  2. View, wrapper (parentview)
  3. Horizontal Stackview that will contain two labels (stacktmp)
  4. Labels x2 (tx, tx2)

Additionally: mystack has 4 constraints: leading, trailing, top and bottom are the same as "Safe view".

The code:

let parentview = UIView()
parentview.backgroundColor = UIColor.cyan
let stacktmp = UIStackView()
stacktmp.axis = .horizontal

let tx = UILabel()
tx.text = "ss"
tx.backgroundColor = UIColor.red
tx.font = UIFont.boldSystemFont(ofSize: 19)

let tx2 = UILabel()
tx2.text = "This is a long sentence to check whether the view and the stackview adapt successfully to the length of this label."
//tx2.numberOfLines = 0
stacktmp.addArrangedSubview(tx)
stacktmp.addArrangedSubview(tx2)

parentview.addSubview(stacktmp)

stacktmp.translatesAutoresizingMaskIntoConstraints = false
print(parentview.frame.size.height)
stacktmp.topAnchor.constraint(equalTo: parentview.topAnchor).isActive = true
stacktmp.heightAnchor.constraint(equalTo:    parentview.heightAnchor).isActive = true

mystack.addArrangedSubview(parentview)

stacktmp.trailingAnchor.constraint(equalTo: parentview.trailingAnchor, constant: 0).isActive = true
stacktmp.leadingAnchor.constraint(equalTo: parentview.leadingAnchor, constant: 0).isActive = true

What I get:

enter image description here

My goal:

I want the sentence of the second label to break the words and fill it below in more than one line if necessary.

I tried adding the following line: tx2.numberOfLines = 0 (commented in the code)

As a result I got:

enter image description here

It certainly splited the sentence as I wanted but now the first label expanded unnecessarily.

How could a keep the first label as narrow as possible while allowing the second label to use more than a single line if necessary? I've been trying to fix this for several hours already trying to change the constraints but I'm still unable to fix it.


Solution

  • As was commented, Hugging and Compression Resistance Priorities are helpful (needed).

    This should get you what you want:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // create parentview
        let parentview = UIView()
        parentview.translatesAutoresizingMaskIntoConstraints = false
        parentview.backgroundColor = UIColor.cyan
    
        // add parentview to view
        view.addSubview(parentview)
    
        // constrain parentview to Zero all the way around
        parentview.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true
        parentview.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0).isActive = true
        parentview.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
        parentview.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true
    
        // create stack view
        let stacktmp = UIStackView()
        stacktmp.translatesAutoresizingMaskIntoConstraints = false
        stacktmp.axis = .horizontal
    
        // add stack view to parentview
        parentview.addSubview(stacktmp)
    
        // constrain stack view top / leading / trailing at Zero, height equal to parentview height
        stacktmp.topAnchor.constraint(equalTo: parentview.topAnchor, constant: 0.0).isActive = true
        stacktmp.leadingAnchor.constraint(equalTo: parentview.leadingAnchor, constant: 0.0).isActive = true
        stacktmp.trailingAnchor.constraint(equalTo: parentview.trailingAnchor, constant: 0.0).isActive = true
        stacktmp.heightAnchor.constraint(equalTo: parentview.heightAnchor).isActive = true
    
        // create "left" label
        let tx = UILabel()
        tx.text = "ss"
        tx.backgroundColor = UIColor.red
        tx.font = UIFont.boldSystemFont(ofSize: 19)
    
        // set Content Hugging to 252
        tx.setContentHuggingPriority(UILayoutPriority(rawValue: 252), for: .horizontal)
        // set Content Compression Resistance to 1000
        tx.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000), for: .horizontal)
    
        // create "right" label
        let tx2 = UILabel()
        tx2.text = "This is a long sentence to check whether the view and the stackview adapt successfully to the length of this label."
        // Zero lines, to get word wrapping
        tx2.numberOfLines = 0
    
        // set Content Hugging to 252
        tx2.setContentHuggingPriority(UILayoutPriority(rawValue: 252), for: .horizontal)
        // set Content Compression Resistance to 1000
        tx2.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000), for: .horizontal)
    
        // add labels to stack view
        stacktmp.addArrangedSubview(tx)
        stacktmp.addArrangedSubview(tx2)
    
    }
    

    Result:

    enter image description here