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对多行文本支持有限。
问题原由分析
- UILabel问题:直接给
attributedText设置固定大小的font时,富文本样式是静态的,系统不会自动缩放其中的字体;必须让label的font属性与富文本中的font关联,才能触发缩容逻辑。 - 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值,无变化 - 确认字体已正确加载
- 检查自动布局约束无异常
疑问
- 为何
minimumScaleFactor被忽略?代码中是否存在阻止生效的逻辑? - 是否遗漏了Interface Builder或代码中的特定设置?是否与布局约束有关?
- 该问题是否与目标iOS版本的bug相关?还是样式应用方式有误?
环境信息
- Xcode版本:15.4 (15F31d)
- Swift版本:5.10
- iOS最低部署版本:15.3
内容的提问来源于stack exchange,提问作者Артур Рыб</think_never_used_51bce0c785ca2f68081bfa7d91973934>
相关产品推荐
相关产品推荐

