简体   繁体   English

确定具有最大宽度的多行UILabel的最大字体大小

[英]Determining the maximum font size for a multi-line UILabel with maximum width

Now I know there are dozens of questions that ask this same thing however most of them dont pertain to multi-line labels or have answers that dont work or are outdated. 现在,我知道有数十个问题问同样的问题,但是大多数问题与多行标签无关,或者答案不起作用或已过时。 I have looked. 我看了

I am trying to figure out the minimum font size needed to display message inside a 3 line UILabel taking up only maximumContentWidth width and with font UIFont.systemFont(.regular) . 我试图找出以显示所需的最小字体大小message 3线的UILabel内占用仅maximumContentWidth宽度并用字体UIFont.systemFont(.regular) Now I realize that there are properties within UILabel that allow it to automatically shrink to fit however that wont work for me. 现在,我意识到UILabel中有一些属性可以使它自动缩小以适合它,但对我不起作用。 I need to determine the specific number for the minimum font size in order to apply it to multiple other UILabels some of them displaying significantly less text. 我需要确定最小字体大小的特定数字,以便将其应用于多个其他UILabel,其中一些显示的文字明显更少。

I do have a maximum font size of 20 and a minimum font size of 13. 我的最大字体大小为20,最小字体大小为13。

I am currently partially using a solution found here however it only works in theory. 我目前正在部分使用这里找到的解决方案但是它仅在理论上有效。 I am not exactly certain why but when I did some test text that was great on strings like "fa fa fa ..." where fa is repeated until I know visually that one fa cannot fit in maximum font. 我不确定为什么,但是当我在“ fa fa fa ...”这样的字符串上做了一些很棒的测试文本时,重复fa直到我从视觉上知道一个fa不能容纳最大字体。 However for strings like "Ww wwwwwwwww wwww wwww ww wwww www w www www wwwwwww www wwwwwwww wwwwwww. www www wwwwwwwwww wwwwwww wwww www wwwwww www wwwwwwwwww ww wwwwww wwww www 10,000 wwww. wwww ww ww ww, ww www www wwwwwwwww www www wwwww www wwww wwwwwww www wwwwwwwwwwww." 但是,对于“ Ww wwwwwwwww wwww wwww www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www www wwwwwww www wwwwwwwwwwwwwww。” the system completely breaks down not making the text as small as it needs to be. 系统会完全崩溃,无法使文本变小到所需的大小。

So here is the detector 这是探测器

extension UILabel {

    var isTruncated: Bool {

        guard let labelText = text else {
            return false
        }

        let labelTextSize = (labelText as NSString).boundingRect(
            with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
            options: .usesLineFragmentOrigin,
            attributes: [.font: font],
            context: nil).size

        return labelTextSize.height > bounds.size.height
    }
}

And here is how I am using it: 这是我的使用方式:

    var testLabel = UILabel()
    var font = 20
    testLabel.numberOfLines = 3
    testLabel.frame.size.width = maximumContentWidth
    while font > 13 {
        testLabel.text = message
        testLabel.font = UIFont.systemFont(ofSize: font, weight: .regular)
        testLabel.sizeToFit()
        if !testLabel.isTruncated {
            break
        }
        font -= 0.1
    }

Why is this method not working and what is a suitable substitute for it? 为什么这种方法不起作用,什么是合适的替代方法?

If I got your code right, you're trying to decrease font size until it will fit the UILabel size. 如果我的代码正确,则您正在尝试减小字体大小,直到它适合UILabel大小为止。 So you the size of the font would be as large as possible. 因此,字体的大小将尽可能大。

The main problem is in your while loop. 主要问题在于您的while循环中。 On each step, you set up new font and call sizeToFit what makes you label frame change to fit the font size. 在每个步骤上,您都需要设置新font并调用sizeToFit这会使您更改标签框架以适合字体大小。 After that your isTruncated will return false . 之后,您的isTruncated将返回false

You need to set up your UILabel s frame on each step manually, instead of calling sizeToFit() . 您需要在每个步骤上手动设置UILabel的框架,而不是调用sizeToFit()

testLabel.numberOfLines = 3
testLabel.text = message

while font > 13 {
    testLabel.font = UIFont.systemFont(ofSize: font, weight: .regular)
    testLabel.frame.size = CGSize(width: maximumContentWidth,
                                  height: maximumContentHeight)
    if !testLabel.isTruncated {
        break
    }
    font -= 0.1
}

After that, you will set the desired labels size and check if the new font size let the text to fit it. 之后,您将设置所需的标签大小,并检查新的字体大小是否使文本适合它。

UPDATE UPDATE

I didn't mention that you want to make sure you UILabel doesn't have more than 3 line. 我没有提到您要确保UILabel不超过3行。 This is a bit tricky because there is no easy or simple way to know how many lines does UILabel have. 这有点棘手,因为没有简单或简单的方法来知道UILabel有多少行。 But that's the solution that I've used in my projects 但这就是我在项目中使用的解决方案

extension UILabel {
    func getLinesCount() -> Int {
        let text = self.text ?? ""
        let rectWidth = self.frame.width

        let myFont = CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil)
        let attStr = NSMutableAttributedString(string: text)
        let range = NSRange(location: 0, length: attStr.length)
        attStr.addAttribute(kCTFontAttributeName as NSAttributedStringKey, value: myFont, range: range)

        let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString)
        let path: CGMutablePath = CGMutablePath()
        let rect = CGRect(x: 0, y: 0, width: rectWidth, height: CGFloat.greatestFiniteMagnitude)
        path.addRect(rect, transform: .identity)

        let frame: CTFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
        guard let lines = CTFrameGetLines(frame) as? [Any] else { return 0 }
        return lines.count
    }
}

This method returns you a number of lines for your label, based on its font and width . 此方法根据标签的fontwidth ,为您的标签返回多行。 You can use it in your while loop to check how does it change. 您可以在while循环中使用它来检查它如何变化。

Hope it helps you. 希望对您有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM