Swift - 调整 fontSize 以适应布局的宽度(以编程方式)

Swift - Adjusting fontSize to fit the width of the layout (programmatically)

我一直在寻找可以动态调整 fontSize 以适应布局框宽度的东西。但是我能找到的所有答案都是使用这个:

label.adjustsFontSizeToFitWidth = true

哪个有效。但前提是我没有将 setTranslatesAutoresizingMaskIntoConstraints 设置为 false.

请注意,我不使用故事板。所以要完全控制我的其他约束,我需要这一行:

label.setTranslatesAutoresizingMaskIntoConstraints(false)

那么如何在不使用情节提要和无法使用的情况下调整字体大小以适应宽度adjustsFontSizeToFitWidth

在我弄清楚如何调整字体大小以适合宽度之后。我还需要调整布局框的高度以适应字体大小。虽然似乎有这方面的文档,但如果您碰巧也知道这个问题的答案,我们将不胜感激。

提前致谢

为您的标签尝试以下命令:

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2

并尝试将标签的行更改为 0 和 1(检查两种情况):

label.numberOfLines = 0 // or 1

我只是做了您需要的,效果很好! (仅以编程方式)- 我们正在为标签设置大字体,以便将其重新调整为完美的字体大小。

self.label.font = UIFont(name: "Heiti TC", size: 60)
self.label.numberOfLines = 0
self.label.minimumScaleFactor = 0.1
self.label.baselineAdjustment = .alignCenters
self.label.textAlignment  = .center

如果您使用的是自动版式,请在 viewDidLayoutSubviews 中执行此代码(在布局完成后)。

你的,Roi

MinimumScaleFactor 范围是 0 到 1。所以我们根据我们的字体大小设置 MinimumScaleFactor 如下

Objective C

[lb setMinimumScaleFactor:10.0/[UIFont labelFontSize]];
lb.adjustsFontSizeToFitWidth = YES;

Swift 3.0

lb.minimumScaleFactor = 10/UIFont.labelFontSize
lb.adjustsFontSizeToFitWidth = true

我不知道这是否能完全回答您的问题,但您可以使用此扩展来计算适合您自己的字体大小。

Swift 3

extension String {
   func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat {
       let constraintSize = CGSize(width: width, height: .max)
       let boundingBox = self.boundingRectWithSize(constraintSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

       return boundingBox.height
   }

   func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat {
       let constrainedSize = CGSize(width: .max, height: height)
       let boundingBox = self.boundingRectWithSize(constrainedSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

       return boundingBox.width
   }
}

更新 - 添加示例并更新代码 Swift 5

Swift 5

extension String {
    func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

        return boundingBox.height
    }

    func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat {
        let constrainedRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constrainedRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

        return boundingBox.width
    }
}

我的逻辑是确保两个不同的标签具有相同的字体大小。在我的例子中,它是用户名字和姓氏的两个标签。我为此需要两个标签的原因是因为每个标签都是独立动画的。

class ViewController: UIViewController {
      ...

      func viewDidLoad() {
         super.viewDidLoad()
         fixFontSizes()
         ...
      }

      func fixFontSizes() {
         let leadingMargin = self.leadingContainerConstraint.constant
         let trailingMargin = self.trailingContainerConstraint.constant
         let maxLabelWidth = self.view.bounds.width - leadingMargin - trailingMargin

         let firstName = self.firstNameLabel.text ?? ""
         let lastName = self.lastNameLabel.text ?? ""

         let firstNameWidth = firstName.width(constrainedBy: self.container.bounds.height, with: self.firstNameLabel.font)
         let lastNameWidth = lastName.width(constrainedBy: self.container.bounds.height, with: self.lastNameLabel.font)

         let largestLabelWidth = max(firstNameWidth, lastNameWidth)
         guard largestLabelWidth > maxLabelWidth else { return }

         let largestTextSize = max(self.firstNameLabel.font.pointSize, self.lastNameLabel.font.pointSize)

         let labelToScreenWidthRatio = largestLabelWidth / maxLabelWidth
         let calculatedMaxTextSize = floor(largestTextSize / labelToScreenWidthRatio)

         self.firstNameLabel.font = self.firstNameLabel.font.withSize(calculatedMaxTextSize)
         self.lastNameLabel.font = self.lastNameLabel.font.withSize(calculatedMaxTextSize)
      }


}

这是一个 hack 解决方案:

var size: CGFloat = 20

    while titleLabel.frame.width > containerView.frame.width {

        titleLabel.font = UIFont.systemFont(ofSize: size)
        titleLabel.sizeToFit()
        size -= 1

    }

Swift 上面的4个转换:

extension String
{
    func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat
    {
        let constraintSize = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

        return boundingBox.height
    }

    func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat
    {
        let constrainedSize = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constrainedSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)

        return boundingBox.width
    }
}

Swift 5

extension String
{
    func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat
    {
        let constraintSize = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)

        return boundingBox.height
    }

    func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat
    {
        let constrainedSize = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constrainedSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)

        return boundingBox.width
    }
}