Yi-An
Yi-An

Reputation: 113

UILabel sizeToFit not count long word-wrap line break

I tried to use sizeToFit to let the UILabel height is dynamically change as the text. However, it do count "\n", but it seems not counting long word wrapping to new line. The text will eventually overflow.

In the code, I first add a scrollview and a stackview, and create two functions to setup their constraint and background color. When everything is done, I tried to write a for-loop, creating UIView with UILabel, and using

label.numberOfLines = 0

label.lineBreakMode = NSLineBreakMode.byWordWrapping

to let long word wrapped. And I create a for-loop to get longer string.

label.text = "This is first line and it is very very long long long."
            for _ in 0...i{
                label.text! += "\n"+"This is new added line and is also very very long long long"
            }

The original code is as below if needed.

I can't figure out which step is going wrong.

Thanks for helping me.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor(red: 213/255, green: 165/255, blue: 68/255, alpha: 1)
        //scroll and stack view adjust
        let scrollView = UIScrollView()
        scrollViewAdjust(scrollView: scrollView)
        let stackView = UIStackView()
        stackViewAdjust(stackView: stackView, scrollView: scrollView)
        
        for i in 0..<5{
            let newView = UIView()
            stackView.addArrangedSubview(newView)
            newView.translatesAutoresizingMaskIntoConstraints = false
            newView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
            newView.layer.cornerRadius = 5
            let label = UILabel()
            newView.addSubview(label)
            label.translatesAutoresizingMaskIntoConstraints = false
            label.numberOfLines = 0
            label.lineBreakMode = NSLineBreakMode.byWordWrapping
            label.text = "This is first line and it is very very long long long."
            for _ in 0...i{
                label.text! += "\n"+"This is new added line and is also very very long long long"
            }
            label.topAnchor.constraint(equalTo: newView.topAnchor).isActive = true
            label.leadingAnchor.constraint(equalTo: newView.leadingAnchor, constant: 3).isActive = true
            label.trailingAnchor.constraint(equalTo: newView.trailingAnchor, constant: 3).isActive = true
            label.sizeToFit()
            print(label.frame.size.height)
            newView.heightAnchor.constraint(equalToConstant: label.frame.size.height).isActive = true
        }
        
        
    }
    
    //functions
    func scrollViewAdjust(scrollView: UIScrollView){
        view.addSubview(scrollView)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 6).isActive = true
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    }
    
    func stackViewAdjust(stackView:UIStackView, scrollView:UIScrollView){
        stackView.axis = .vertical
        stackView.spacing = 20
        scrollView.addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
        stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 0.8).isActive = true
        stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 15).isActive = true
        stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    }
}

Upvotes: 0

Views: 678

Answers (2)

elliott-io
elliott-io

Reputation: 1414

You must set a label width when you create it. I've updated the for loop from your example here to match the width of your stackView:

    for i in 0..<5{
        let newView = UIView()
        stackView.addArrangedSubview(newView)
        newView.translatesAutoresizingMaskIntoConstraints = false
        newView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
        newView.layer.cornerRadius = 5
        stackView.layoutIfNeeded() // needed to force update the layout before getting the width
        let width = stackView.frame.width
        print(width)
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        newView.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.textColor = UIColor.black
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        label.text = "This is \(i) line and it is very very long long long."
        for ii in 0...i{
            label.text! += "\n"+"This is new added \(ii) line and is also very very long long long"
        }
        label.sizeToFit()
        label.topAnchor.constraint(equalTo: newView.topAnchor).isActive = true
        label.leadingAnchor.constraint(equalTo: newView.leadingAnchor, constant: 3).isActive = true
        label.trailingAnchor.constraint(equalTo: newView.trailingAnchor, constant: 3).isActive = true
        label.bottomAnchor.constraint(equalTo: newView.bottomAnchor).isActive = true
        print(label.frame.size.height)
        newView.heightAnchor.constraint(equalToConstant: label.frame.size.height).isActive = true
    }

While this works and does scroll, you should really be using a UICollectionView to custom UICollectionViewCell's to handle a scroll like this.

Upvotes: 1

Jawad Ali
Jawad Ali

Reputation: 14397

Your trailing constraint is not. correct

label.trailingAnchor.constraint(equalTo: newView.trailingAnchor, constant: 3).isActive = true

its going out of newView ... set it like this to give 3 points padding

label.trailingAnchor.constraint(equalTo: newView.trailingAnchor, constant: -3).isActive = true

Upvotes: 0

Related Questions