如何让UILabel实现多行自动缩放且适配宽度超标的单个单词?
UILabel多行+字体自动缩放适配超长单词解决方案
失效原因
原生UILabel的adjustsFontSizeToFitWidth在多行(numberOfLines = 0)场景下默认优先通过换行适配内容,且你当前使用的.byTruncatingTail换行模式会让系统优先选择截断尾部内容而非缩放字体;同时未设置minimumScaleFactor最小缩放比例,也会导致缩放逻辑无法触发,最终出现单个超长单词适配异常的问题。
方案一:修改系统配置(优先推荐,改动最小)
直接调整UILabel的属性即可覆盖90%以上常规场景:
textLabel.numberOfLines = 0 textLabel.adjustsFontSizeToFitWidth = true // 按业务需求设置最小缩放比例,示例为最小缩放到原字号的50% textLabel.minimumScaleFactor = 0.5 // 替换原有的byTruncatingTail,保证超长单词无法拆行时触发缩放 textLabel.lineBreakMode = .byClipping // 可选开启:允许系统自动收紧字符间距提升适配效果 textLabel.allowsDefaultTighteningForTruncation = true
方案二:手动计算适配字号(复杂场景用)
如果系统配置无法满足你的定制化需求,可以手动计算适合当前Label尺寸的最大可用字号:
/// 计算适配指定尺寸的最大可用字体 /// - Parameters: /// - text: 要展示的文本 /// - maxWidth: Label的最大可用宽度 /// - maxHeight: Label的最大可用高度 /// - originalFont: 原始字号的字体 /// - minScale: 允许的最小缩放比例 /// - Returns: 适配后的字体 func getAdjustedFont(text: String, maxWidth: CGFloat, maxHeight: CGFloat, originalFont: UIFont, minScale: CGFloat) -> UIFont { let minFontSize = originalFont.pointSize * minScale var currentSize = originalFont.pointSize while currentSize >= minFontSize { let testFont = originalFont.withSize(currentSize) let boundingRect = text.boundingRect( with: CGSize(width: maxWidth, height: .greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [.font: testFont], context: nil ) if boundingRect.height <= maxHeight { return testFont } currentSize -= 1 } return originalFont.withSize(minFontSize) } // 调用示例 // 注意:需要在Label布局完成、拿到准确的bounds后调用 textLabel.font = getAdjustedFont( text: textLabel.text ?? "", maxWidth: textLabel.bounds.width, maxHeight: textLabel.bounds.height, originalFont: UIFont.systemFont(ofSize: 17), minScale: 0.5 )
手动计算注意事项
- 必须在Label布局完成后调用计算方法,自动布局场景可在
viewDidLayoutSubviews(ViewController中)或layoutSubviews(自定义View中)触发 - 若需要支持动态更新文本,每次更新文本后需重新计算字体大小
内容的提问来源于stack exchange,提问作者GBasher
相关产品推荐
相关产品推荐

