SizeToFit() doesn't work properly with \n?

92 views Asked by At

I create a label programmatically. It will always have two lines. However, the font size of these two lines will change. Therefore, the height and width of the label will have to change. I try to do this using sizeToFit. However, the second word ("Day") is only partially shown. The bottom part of the word is cut off. It is as if sizeToFit does not recognize that the text is actually two lines. It is as if sizeToFit is adjusting the size of the label to fit one line. How do I solve this? Thanks.

let screenWidth = UIScreen.main.bounds.width
let screenWidthHalf = screenWidth/2.0
let screenHeight = UIScreen.main.bounds.height
myLabel = UILabel()
myLabel.text = "Good \n Day"
myLabel.textAlignment = .center
let myLabelFontSize = 12.0*screenHeight/667
let myLabelFont = UIFont.systemFont(ofSize: myLabelFontSize)
myLabel.font = myLabelFont
myLabel.numberOfLines = 0
myLabel.sizeToFit()
let myLabelWidth = myLabel.frame.width
let myLabelWidthHalf = myLabelWidth/2.0
let myLabelX = screenWidthHalf - myLabelWidthHalf
let myLabelY = 142.5
myLabel.frame.origin.x = myLabelX
myLabel.frame.origin.y = myLabelY
scrollView.addSubview(myLabel)
1

There are 1 answers

0
David J On

I like to use the method presented by Lets Build That App channel (checkout the Facebook News Feed Dynamic Cell Content), instead of sizeToFit. I do use scrollviews. This is a typical method I use to get the height. Definitely takes into font size, newlines, and just about anything else I've been able to give it.

Basically the method is as follows, when I layout the views, I calculated the estimated size of each view based upon it's content, and then use those calculations to update the frame accordingly. I created an extension to UILabel to simplify this. You do need to clear about at least the height or width. Usually the width is clear.

extension UILabel {
  func getEstimatedHeight(width: CGFloat) -> CGFloat {
    let size = CGSize(width: width, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let estimatedFrame = NSString(string: self.text ?? "").boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: self.font], context: nil)
    return estimatedFrame.height
  }
}

You may also have to add a "fudging" factor to your height after it is returned.

 let myViewEstimatedHeight = toView.getEstimatedHeight(width: width - 100)
 myView.view.frame = CGRect(x: 20, y: 20, width: width, 
       height: myViewEstimatedHeight + 3)