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

相关推荐
Java手札12 分钟前
安装如下依赖(package.json 未包含):vueelement-plusecharts@element-plus/icons-vue
前端·javascript·vue.js
EndingCoder17 分钟前
Three.js + AI:结合 Stable Diffusion 生成纹理贴图
开发语言·前端·javascript·人工智能·stable diffusion·ecmascript·three.js
haruma sen21 分钟前
VUE前端
前端
汪叽家的兔子羡22 分钟前
vue模块化导入
前端·javascript·vue.js·typescript·vue3·vue2·vite
植物系青年28 分钟前
300 行代码!手把手教你写一个简版 Vue3 框架 📣
前端·vue.js
秉承初心29 分钟前
Vue3与ES6+的现代化开发实践(AI)
前端·vue.js·es6
Spirited_Away34 分钟前
脚手架开发之多包管理(npm, yarn, pnpm workspaces)
前端·面试
iaku36 分钟前
🔥React高级特性实战:错误边界、Portals与Refs进阶
前端·react.js·trae
薛定谔的猫239 分钟前
type-challenges系列(番外):技巧与知识点
前端·typescript
tiantian_cool1 小时前
Xcode 导入与使用 SVG 文件矢量图适配全流程
前端