【问题标题】:Determining the maximum font size for a multi-line UILabel with maximum width确定具有最大宽度的多行 UILabel 的最大字体大小
【发布时间】:2018-09-19 08:31:22
【问题描述】:

现在我知道有几十个问题会问同样的问题,但其中大多数与多行标签无关,或者答案无效或已过时。我看过了。

我试图找出在仅占用maximumContentWidth 宽度和字体UIFont.systemFont(.regular) 的3 行UILabel 内显示message 所需的最小字体大小。现在我意识到 UILabel 中有一些属性可以让它自动缩小以适应,但这对我不起作用。我需要确定最小字体大小的具体数字,以便将其应用于多个其他 UILabel,其中一些 UILabel 显示的文本显着减少。

我的最大字体大小为 20,最小字体大小为 13。

我目前正在部分使用here 找到的解决方案,但它仅在理论上有效。我不完全确定为什么,但是当我在“fa fa fa ...”之类的字符串上做了一些很棒的测试文本时,重复 fa 直到我从视觉上知道一个 fa 不能适应最大字体。但是对于像“Ww wwwwwww wwww wwww ww wwww www www www wwwwwww www wwwwwwwwww wwwwwww www www wwwwwwwww www wwwwwwwwww www www www www 10,000 wwww www www www www www www www www www www www www万维网万维网万维网万维网。”系统完全崩溃,没有使文本尽可能小。

所以这里是检测器

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
    }
}

这是我的使用方法:

    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
    }

为什么这种方法不起作用,什么是合适的替代品?

【问题讨论】:

  • 嗯,你的例子是什么时候坏了,我怀疑 13 号的尺寸不够小。

标签: ios swift xcode uikit


【解决方案1】:

如果我的代码正确,您会尝试减小字体大小,直到它适合 UILabel 大小。所以你字体的大小会尽可能的大。

主要问题在于您的while 循环。在每一步中,您设置新的font 并调用sizeToFit 是什么让您更改标签框架以适应字体大小。之后您的isTruncated 将返回false

您需要在每一步手动设置UILabels 框架,而不是调用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
}

之后,您将设置所需的标签大小并检查新的字体大小是否让文本适合它。

更新

我没有提到你想确保你 UILabel 没有超过 3 行。这有点棘手,因为没有简单的方法可以知道UILabel 有多少行。但这是我在项目中使用的解决方案

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
    }
}

此方法会根据标签的fontwidth 返回标签行数。您可以在 while 循环中使用它来检查它是如何变化的。

希望对你有帮助。

【讨论】:

  • 虽然此解决方案确实确保文本适合,但不能确保它适合 3 行。修正了我在原始问题代码中的拼写错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 2015-05-07
  • 2011-11-17
相关资源
最近更新 更多