UILabel 字体缩放适应宽度

在iOS开发中,UILabel本身没有直接提供"最大字体"的属性,但可以通过以下几种方式实现字体大小的上限控制:

一、手动计算并设置字体大小

在设置文本后,根据文本内容和可用空间动态计算合适的字体大小,确保不超过预设的最大值:

swift 复制代码
func adjustFontSize(for label: UILabel, maxFontSize: CGFloat) {
    let originalFont = label.font
    var fontSize = maxFontSize
    
    // 逐步减小字体大小,直到文本适应标签宽度
    while fontSize > 10 { // 设置最小字体限制
        let testFont = UIFont(descriptor: originalFont.fontDescriptor, size: fontSize)
        let attributes = [NSAttributedString.Key.font: testFont]
        let textSize = label.text?.size(withAttributes: attributes) ?? .zero
        
        if textSize.width <= label.bounds.width {
            label.font = testFont
            return
        }
        
        fontSize -= 1
    }
    
    // 如果减小到最小值仍不适应,使用最小字体
    label.font = UIFont(descriptor: originalFont.fontDescriptor, size: 10)
}

// 使用示例
label.text = "这是一段可能需要调整字体大小的长文本"
adjustFontSize(for: label, maxFontSize: 24) // 最大字体为24pt

二、使用iOS 14+的Proportional Font Scaling

iOS 14引入了UIFontMetricsscaledFont(for:maximumPointSize:)方法,可以自动缩放字体并设置上限:

swift 复制代码
// 设置最大字体大小(例如24pt)
let maxFontSize: CGFloat = 24
let font = UIFont.systemFont(ofSize: 17) // 基础字体大小

// 自动缩放字体,同时限制最大尺寸
label.font = UIFontMetrics.default.scaledFont(for: font, maximumPointSize: maxFontSize)

// 确保支持动态类型(用户字体大小偏好)
label.adjustsFontForContentSizeCategory = true

三、使用UILabel的adjustsFontSizeToFitWidth

如果只需要在单行文本超出宽度时缩小字体,可以启用adjustsFontSizeToFitWidth,并结合minimumScaleFactor设置最小缩放比例:

swift 复制代码
label.adjustsFontSizeToFitWidth = true // 自动缩小字体以适应宽度
label.minimumScaleFactor = 0.5 // 最小缩放至原字体的50%
label.numberOfLines = 1 // 确保单行显示

// 设置字体,例如最大为24pt
let originalFont = UIFont.systemFont(ofSize: 24)
label.font = originalFont

这种方法的局限性在于:

  1. 只能缩小不能放大(如果文本很短,字体不会超过原始大小)。
  2. 只处理宽度,不处理高度(多行文本时可能需要结合其他方法)。

四、自定义UILabel子类

封装上述逻辑到自定义UILabel子类中,便于复用:

swift 复制代码
class BoundedSizeLabel: UILabel {
    var maxFontSize: CGFloat = 24
    
    override func layoutSubviews() {
        super.layoutSubviews()
        adjustFontSize()
    }
    
    private func adjustFontSize() {
        guard let text = text, let currentFont = font else { return }
        
        // 使用UIFontMetrics计算适合的字体大小
        let scaledFont = UIFontMetrics.default.scaledFont(for: currentFont)
        let constraintRect = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
        
        let boundingBox = text.boundingRect(
            with: constraintRect,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: [.font: scaledFont],
            context: nil
        )
        
        // 如果文本高度超过标签高度,逐步减小字体
        if boundingBox.height > bounds.height {
            var fontSize = scaledFont.pointSize
            while fontSize > 10 && boundingBox.height > bounds.height {
                fontSize -= 1
                let smallerFont = UIFont(descriptor: currentFont.fontDescriptor, size: fontSize)
                let smallerBoundingBox = text.boundingRect(
                    with: constraintRect,
                    options: [.usesLineFragmentOrigin, .usesFontLeading],
                    attributes: [.font: smallerFont],
                    context: nil
                )
                
                if smallerBoundingBox.height <= bounds.height || fontSize <= 10 {
                    font = smallerFont
                    break
                }
            }
        } else if scaledFont.pointSize > maxFontSize {
            // 如果计算出的字体超过最大值,使用最大值
            font = UIFont(descriptor: currentFont.fontDescriptor, size: maxFontSize)
        }
    }
}

// 使用示例
let boundedLabel = BoundedSizeLabel()
boundedLabel.maxFontSize = 24
boundedLabel.text = "自定义最大字体的标签"

五、结合自动布局

如果使用自动布局,确保为UILabel设置了明确的宽度约束,否则自适应计算可能不准确:

swift 复制代码
// 示例:设置UILabel最大宽度为父视图的80%
label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true

// 应用字体大小限制
label.font = UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 17), maximumPointSize: 24)
label.adjustsFontForContentSizeCategory = true

注意事项

  1. 多行文本:对于多行文本,需同时考虑宽度和高度的约束。
  2. 动态类型 :如果支持用户字体大小偏好(Dynamic Type),建议结合UIFontMetrics使用。
  3. 性能:频繁计算文本大小可能影响性能,建议在必要时调用(如文本变化或布局更新后)。

通过以上方法,你可以灵活控制UILabel的字体大小上限,确保文本在不同场景下都能正确显示。

相关推荐
键盘不能没有CV键3 小时前
【图片处理】✈️HTML转图片字体异常处理
前端·javascript·html
yantuguiguziPGJ4 小时前
WPF 联合 Web 开发调试流程梳理(基于 Microsoft.Web.WebView2)
前端·microsoft·wpf
大飞记Python4 小时前
部门管理|“编辑部门”功能实现(Django5零基础Web平台)
前端·数据库·python·django
tsumikistep5 小时前
【前端】前端运行环境的结构
前端
你的人类朋友5 小时前
【Node】认识multer库
前端·javascript·后端
Aitter5 小时前
PDF和Word文件转换为Markdown的技术实现
前端·ai编程
mapbar_front6 小时前
面试问题—上家公司的离职原因
前端·面试
昔人'6 小时前
css使用 :where() 来简化大型 CSS 选择器列表
前端·css
昔人'6 小时前
css `dorp-shadow`
前端·css
流***陌7 小时前
扭蛋机 Roll 福利房小程序前端功能设计:融合趣味互动与福利适配
前端·小程序