You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UILabel与UIButton设置自动缩容字体无效,求排查原因

UILabel和UIButton设置自动缩容字体无效问题

解决方案

针对UILabel的修复

当使用attributedText时,系统不会自动缩放其中的固定字体,需调整实现逻辑,让label的基础字体配置与富文本关联:

static func styleLabel(label: UILabel, textLabel: String) {
    let fontName = "Montserrat-Medium"
    let fontSize: CGFloat = 18
    let minimumFontSize: CGFloat = 6

    guard let baseFont = UIFont(name: fontName, size: fontSize) else {
        fatalError("Failed to load font \(fontName).")
    }

    // 先配置label的自动缩放核心属性
    label.numberOfLines = 0
    label.textAlignment = .center
    label.lineBreakMode = .byWordWrapping
    label.font = baseFont
    label.adjustsFontSizeToFitWidth = true
    label.minimumScaleFactor = minimumFontSize / fontSize
    label.baselineAdjustment = .alignCenters // 确保缩放时文本对齐正常
    
    let textColor = UIColor(hex: "FFFFFF")
    // 基于label当前的font构建富文本(后续系统缩放时会同步更新)
    let kernValue = label.font.pointSize * 0.2
    let labelAttributedString = NSMutableAttributedString(
        string: textLabel,
        attributes: [
            .font: label.font,
            .kern: kernValue,
            .foregroundColor: textColor
        ]
    )

    label.attributedText = labelAttributedString
}

针对UIButton的修复

numberOfLines=0会让文本自动换行,系统判定无需缩放;同时.byClipping的换行模式也会阻止缩容逻辑,需调整配置:

static func styleButton(
    _ button: UIButton,
    title: String,
    fontName: String = "Montserrat-Medium",
    fontSize: CGFloat = 18,
    minimumFontSize: CGFloat = 6,
    cornerRadius: CGFloat = 20,
    backgroundColor: UIColor,
    titleColor: UIColor
) {
    guard let font = UIFont(name: fontName, size: fontSize) else {
        fatalError("Failed to load font \(fontName).")
    }

    // 先配置titleLabel的自动缩放属性
    button.titleLabel?.numberOfLines = 1 // 改为单行触发缩容
    button.titleLabel?.adjustsFontSizeToFitWidth = true
    button.titleLabel?.minimumScaleFactor = minimumFontSize / fontSize
    button.titleLabel?.lineBreakMode = .byTruncatingTail // 适配单行的截断模式
    button.titleLabel?.baselineAdjustment = .alignCenters

    // 设置按钮样式
    button.setTitle(title, for: .normal)
    button.titleLabel?.font = font
    button.setTitleColor(titleColor, for: .normal)

    button.backgroundColor = backgroundColor
    button.layer.cornerRadius = cornerRadius
}

如果确实需要按钮支持多行文本+自动缩放,需自定义实现文本尺寸计算逻辑,系统默认的adjustsFontSizeToFitWidth对多行文本支持有限。


问题原由分析

  1. UILabel问题:直接给attributedText设置固定大小的font时,富文本样式是静态的,系统不会自动缩放其中的字体;必须让label的font属性与富文本中的font关联,才能触发缩容逻辑。
  2. UIButton问题:numberOfLines=0会让文本自动换行,系统判断文本可通过换行容纳,因此不会触发字体缩放;.byClipping的换行模式也会跳过缩容判断。

原问题详情

问题现象

使用Swift开发iOS项目,期望文本无法容纳时,UILabel和UIButton的字体自动缩小,但设置adjustsFontSizeToFitWidth和minimumScaleFactor后字体完全无变化。

原代码

struct UIStyling {
    static func styleLabel(label: UILabel, textLabel: String) {
        let fontName = "Montserrat-Medium"
        let fontSize: CGFloat = 18
        let minimumFontSize: CGFloat = 6

        guard let font = UIFont(name: fontName, size: fontSize) else {
            fatalError("Failed to load font \(fontName).")
        }

        let kernValue = fontSize * 0.2
        let textColor = UIColor(hex: "FFFFFF")

        label.numberOfLines = 0
        label.textAlignment = .center
        label.lineBreakMode = .byWordWrapping
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = minimumFontSize / fontSize

        let labelAttributedString = NSMutableAttributedString(
            string: textLabel,
            attributes: [
                .font: font,
                .kern: kernValue,
                .foregroundColor: textColor
            ]
        )

        label.attributedText = labelAttributedString
    }

    static func styleButton(
        _ button: UIButton,
        title: String,
        fontName: String = "Montserrat-Medium",
        fontSize: CGFloat = 18,
        minimumFontSize: CGFloat = 6,
        cornerRadius: CGFloat = 20,
        backgroundColor: UIColor,
        titleColor: UIColor
    ) {
        guard let font = UIFont(name: fontName, size: fontSize) else {
            fatalError("Failed to load font \(fontName).")
        }

        button.titleLabel?.adjustsFontSizeToFitWidth = true
        button.titleLabel?.minimumScaleFactor = minimumFontSize / fontSize
        button.titleLabel?.numberOfLines = 0
        button.titleLabel?.lineBreakMode = .byClipping

        button.setTitle(title, for: .normal)
        button.titleLabel?.font = font
        button.setTitleColor(titleColor, for: .normal)

        button.backgroundColor = backgroundColor
        button.layer.cornerRadius = cornerRadius
    }
}

func buttonStyles(for sceneType: SceneType) -> (fontName: String, backgroundColors: [(UIColor, UIColor)], textColors: (UIColor, UIColor)) {
    switch sceneType {
    case .egypt:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#FFD700").withAlphaComponent(0.8), UIColor(hex: "#333333")),
                (UIColor(hex: "#006400").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF"))
            ],
            textColors: (UIColor(hex: "#333333"), UIColor(hex: "#FFFFFF"))
        )
    case .future:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#1E90FF").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF")),
                (UIColor(hex: "#D3D0D0").withAlphaComponent(0.8), UIColor(hex: "#090909"))
            ],
            textColors: (UIColor(hex: "#FFFFFF"), UIColor(hex: "#090909"))
        )
    case .main:
        return (
            fontName: "Montserrat-Medium",
            backgroundColors: [
                (UIColor(hex: "#FFD700").withAlphaComponent(0.8), UIColor(hex: "#333333")),
                (UIColor(hex: "#1E90FF").withAlphaComponent(0.8), UIColor(hex: "#FFFFFF"))
            ],
            textColors: (UIColor(hex: "#333333"), UIColor(hex: "#FFFFFF"))
        )
    }
}

func updateUI() {
    let currentScene = storyBrain.getCurrentScene()

    UIStyling.styleLabel(label: textLabel, textLabel: currentScene.title)

    let styles = buttonStyles(for: currentScene.sceneType)

    UIStyling.styleButton(button1,
                          title: currentScene.button1,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[0].0,
                          titleColor: styles.textColors.0)

    UIStyling.styleButton(button2,
                          title: currentScene.button2,
                          fontName: styles.fontName,
                          backgroundColor: styles.backgroundColors[1].0,
                          titleColor: styles.textColors.1)

    button1.layer.cornerRadius = Style.cornerRadius
    button2.layer.cornerRadius = Style.cornerRadius

    background.image = UIImage(named: currentScene.backgroundImage)

    print("Label size: \(textLabel.frame.size)")
    print("Minimum scale factor: \(textLabel.minimumScaleFactor)")
    print("Font size: \(textLabel.font.pointSize)")
}

已尝试的解决措施

  • 代码方式设置adjustsFontSizeToFitWidth和minimumScaleFactor,无效果
  • 调整minimumFontSize值,无变化
  • 确认字体已正确加载
  • 检查自动布局约束无异常

疑问

  1. 为何minimumScaleFactor被忽略?代码中是否存在阻止生效的逻辑?
  2. 是否遗漏了Interface Builder或代码中的特定设置?是否与布局约束有关?
  3. 该问题是否与目标iOS版本的bug相关?还是样式应用方式有误?

环境信息

  • Xcode版本:15.4 (15F31d)
  • Swift版本:5.10
  • iOS最低部署版本:15.3

内容的提问来源于stack exchange,提问作者Артур Рыб</think_never_used_51bce0c785ca2f68081bfa7d91973934>

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:47:02