Swift 3 - Adjust Font Size to Fit Width, Multiple Lines

守給你的承諾、 提交于 2019-12-04 03:11:39

Interesting question. Here's my solution:

let labelText = self.mylabel.text //where mylabel is the label
let labelSeperated = self.labelText.components(seperatedBy: " ")
if labelSeperated.count > 1 {
    myLabel.lineBreakMode = .byWordWrapping
    myLabel.numberOfLines = 0 
} else {
    myLabel.numberOfLines = 1
    myLabel.adjustsFontSizeToFitWidth = true 
}

Put this code where the label will be changed. It sets the line number to 0 if there are two or more numbers, otherwise set to 1 line only.

If you want to resize multi-line labels, check out this blog post.

Krunal

This will work..

  • Set minimum scale factor for your label. as shown in this image.
  • Set number of lines = 2 // or zero (0) if you want more number of lines
  • Set line breaking mode to '.byTruncatingTail' for 2 lines

Swift 3
Set number of lines zero for dynamic text information, it will be useful for varying text.

var label = UILabel()
let stringValue = "A label\nwith\nmultiline text."
label.text = stringValue
label.numberOfLines = 2 // 0
label.lineBreakMode = .byTruncatingTail // or .byWrappingWord
label.minimumScaleFactor = 0.5 // It is not required but nice to have a minimum scale factor to fit text into label frame

Also, don't set height constraint for your label more than 2 lines.

D. Greg

Swift 5

func setFontForLabel(label:UILabel, maxFontSize:CGFloat, minFontSize:CGFloat, maxLines:Int) {

    var numLines: Int = 1
    var textSize: CGSize = CGSize.zero
    var frameSize: CGSize = CGSize.zero
    let font: UIFont = label.font.withSize(maxFontSize)

    frameSize = label.frame.size

    textSize = (label.text! as NSString).size(withAttributes: [NSAttributedString.Key.font: font])

    // Determine number of lines
    while ((textSize.width/CGFloat(numLines)) / (textSize.height * CGFloat(numLines)) > frameSize.width / frameSize.height) && numLines < maxLines {
        numLines += 1
    }

    label.font = font
    label.adjustsFontSizeToFitWidth = true
    label.numberOfLines = numLines
    label.minimumScaleFactor = minFontSize/maxFontSize
}

Swift 3

I looked at the post that paper111 posted. Unfortunately it's in Obj-C and the sizeWithFont: ,constrainedToSize: , lineBreakMode: method has been deprecated. (- - );

His answer was good, but still didn't provide a fixed size. What I did was to start with a UILabel that had everything but the height (this is probably the same for most people).

let myFrame = CGRect(x: 0, y:0, width: 200, height: self.view.height)
let myLbl = UILabel(frame: myFrame)
let finalHeight:CGFloat = 300

myLbl.font = UIFont(name: "Chalkduster", size: 16.0)
myLbl.lineBreakMode = .byWordWrapping
myLbl.numberOfLines = 0
myLbl.text = "Imagine your long line of text here"
addSubview(myLbl)
myLbl.sizeToFit()

guard myLbl.frame.height > finalHeight else { return }
var fSize:CGFloat = 16 //start with the default font size
    repeat {
        fSize -= 2
        myLbl.font = UIFont(name: "Chalkduster", size: fSize)
        myLbl.sizeToFit()
    } while myLbl.frame.height > finalHeight

You can see that there's a guard blocking the resize if it's not needed. Also, calling sizeToFit() many times isn't ideal, but I can't think of another way around it. I tried to use myLbl.font.withSize(fSize) in the loop but it wouldn't work, so I used the full method instead.

Hope it works for you!

Bionicle

@Krunal's answer helped me but it doesn't work when you have unknown number of lines so here's the solution I came up with. You can also set the maximum and minimum font size. Hope this helps someone!

Swift 2.2 - Sorry, haven't migrated to Swift 3 yet.

func setFontForLabel(label:UILabel, maxFontSize:CGFloat, minFontSize:CGFloat, maxLines:Int) {

    var numLines: Int = 1
    var textSize: CGSize = CGSizeZero
    var frameSize: CGSize = CGSizeZero
    var font: UIFont = UIFont.systemFontOfSize(maxFontSize)

    frameSize = label.frame.size

    textSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: font])

    // Determine number of lines
    while ((textSize.width/CGFloat(numLines)) / (textSize.height * CGFloat(numLines)) > frameSize.width / frameSize.height) && numLines < maxLines {
        numLines += 1
    }

    label.font = font
    label.adjustsFontSizeToFitWidth = true
    label.numberOfLines = numLines
    label.minimumScaleFactor = minFontSize/maxFontSize
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!