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

相关推荐
fanruitian3 小时前
uniapp android开发 测试板本与发行版本
前端·javascript·uni-app
rayufo3 小时前
【工具】列出指定文件夹下所有的目录和文件
开发语言·前端·python
RANCE_atttackkk3 小时前
[Java]实现使用邮箱找回密码的功能
java·开发语言·前端·spring boot·intellij-idea·idea
2501_944525545 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 支出分析页面
android·开发语言·前端·javascript·flutter
李白你好5 小时前
Burp Suite插件用于自动检测Web应用程序中的未授权访问漏洞
前端
刘一说6 小时前
Vue 组件不必要的重新渲染问题解析:为什么子组件总在“无故”刷新?
前端·javascript·vue.js
徐同保7 小时前
React useRef 完全指南:在异步回调中访问最新的 props/state引言
前端·javascript·react.js
刘一说8 小时前
Vue 导航守卫未生效问题解析:为什么路由守卫不执行或逻辑失效?
前端·javascript·vue.js
一周七喜h8 小时前
在Vue3和TypeScripts中使用pinia
前端·javascript·vue.js
weixin_395448918 小时前
main.c_cursor_0202
前端·网络·算法