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的字体大小上限,确保文本在不同场景下都能正确显示。

相关推荐
烛阴42 分钟前
TypeScript高手密技:解密类型断言、非空断言与 `const` 断言
前端·javascript·typescript
样子20182 小时前
Uniapp 之renderjs解决swiper+多个video卡顿问题
前端·javascript·css·uni-app·html
Nicholas682 小时前
flutterAppBar之SystemUiOverlayStyle源码解析(一)
前端
黑客飓风2 小时前
JavaScript 性能优化实战大纲
前端·javascript·性能优化
emojiwoo3 小时前
【前端基础知识系列六】React 项目基本框架及常见文件夹作用总结(图文版)
前端·react.js·前端框架
张人玉4 小时前
XML 序列化与操作详解笔记
xml·前端·笔记
杨荧4 小时前
基于Python的宠物服务管理系统 Python+Django+Vue.js
大数据·前端·vue.js·爬虫·python·信息可视化
YeeWang5 小时前
🎉 Eficy 让你的 Cherry Studio 直接生成可预览的 React 页面
前端·javascript
gnip5 小时前
Jenkins部署前端项目实战方案
前端·javascript·架构
Orange3015115 小时前
《深入源码理解webpack构建流程》
前端·javascript·webpack·typescript·node.js·es6