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

后端 未结 5 2697
眼角桃花
眼角桃花 2021-02-20 13:53

I have a UILabel and it is set to 42.0 pt font, and the width of the label is set using autoconstraints based on factors other than the label itself (aka the things to the right

相关标签:
5条回答
  • 2021-02-20 14:33

    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.

    0 讨论(0)
  • 2021-02-20 14:34

    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
    

    enter image description here

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

    0 讨论(0)
  • 2021-02-20 14:36

    Swift 5

    extension UILabel{
    func adjustsFontSizeToFit(maxFontSize:CGFloat,width:CGFloat,height:CGFloat) {
        self.numberOfLines = 0
        var fontSize:CGFloat = maxFontSize
        if self.sizeThatFits(CGSize(width: width, height: .infinity)).height > height{
            while self.sizeThatFits(CGSize(width: width, height: .infinity)).height > height{
                fontSize -= 1
                self.font = self.font.withSize(fontSize)
            }
        }
    }
    

    }

    0 讨论(0)
  • 2021-02-20 14:37

    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!

    0 讨论(0)
  • 2021-02-20 14:37

    @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
    }
    
    0 讨论(0)
提交回复
热议问题