Multiline UILabel with adjustsFontSizeToFitWidth

前端 未结 8 1468
北海茫月
北海茫月 2020-12-04 12:16

I have a multiline UILabel whose font size I\'d like to adjust depending on the text length. The whole text should fit into the label\'s frame without truncating it.

相关标签:
8条回答
  • 2020-12-04 13:01

    Swift 4.2:

    //
    //  String+Utility.swift
    //
    //  Created by Philip Engberg on 29/11/2018.
    //  Original code from http://stackoverflow.com/a/4383281/463892 & http://stackoverflow.com/a/18951386
    //
    
    import Foundation
    import UIKit
    
    extension String {
        func fontSize(with font: UIFont, constrainedTo size: CGSize, minimumScaleFactor: CGFloat) -> CGFloat {
            var fontSize = font.pointSize
            let minimumFontSize = fontSize * minimumScaleFactor
    
            var attributedText = NSAttributedString(string: self, attributes: [.font: font])
            var height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], context: nil).size.height
    
            var newFont = font
            //Reduce font size while too large, break if no height (empty string)
            while height > size.height && height != 0 && fontSize > minimumFontSize {
                fontSize -= 1
                newFont = UIFont(name: font.fontName, size: fontSize)!
    
                attributedText = NSAttributedString(string: self, attributes: [.font: newFont])
                height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], context: nil).size.height
            }
    
            // Loop through words in string and resize to fit
            for word in self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines) {
                var width = word.size(withAttributes: [.font: newFont]).width
                while width > size.width && width != 0 && fontSize > minimumFontSize {
                    fontSize -= 1
                    newFont = UIFont(name: font.fontName, size: fontSize)!
                    width = word.size(withAttributes: [.font: newFont]).width
                }
            }
            return fontSize
        }
    }
    
    0 讨论(0)
  • 2020-12-04 13:01

    Thought I would add my own take on the answer:

    I think it's a slight improvement on some of the other answers because:

    1. Caching while looping through words to find the longest by width, to prevent unnecessary calculations
    2. All the label attributes are used when doing size calculations

    https://gist.github.com/chrisjrex/c571056a4b621f7099bcbd5e179f184f

    Note: This solution should only be used when a UILabel has .numberOfLines = 0 and .lineBreakMode = .byWordWrapping

    Otherwise you are better off using: .adjustFontSizeForWidth = true from the standard swift library

    The other answers on this thread were very helpful to me in coming up with my solution, thank you

    0 讨论(0)
提交回复
热议问题