Swift中如何在UILabel/UITextView内实现词语上下对齐排列
实现文本上下对齐不挤压的可行方案
你的实现出现相邻文字右移的核心原因是:baselineOffset仅调整文字垂直位置,目标文本的水平宽度仍然会被富文本排版系统计入布局,自然会挤占后续文字的位置。以下是两种可直接落地的实现方案:
方案1:通过CoreText Run Delegate归零目标文本的布局宽度(推荐)
通过Run Delegate告知排版系统,目标文本不占用水平布局空间,仅做垂直偏移绘制即可,兼容性好,适用于UILabel和UITextView所有场景。
完整实现代码如下:
import CoreText import UIKit extension String { func setSubscriptAligned(text: String, offsetY: CGFloat = -10, font: UIFont = .systemFont(ofSize: 12), color: UIColor = .red) -> NSMutableAttributedString { let attributedString = NSMutableAttributedString(string: self) let foundRange = attributedString.mutableString.range(of: text) guard foundRange.location != NSNotFound else { return attributedString } // 配置Run Delegate,归零布局宽度 var callbacks = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion, dealloc: { _ in }, getAscent: { info -> CGFloat in return UIFont.systemFont(ofSize: 12).ascender }, getDescent: { info -> CGFloat in return UIFont.systemFont(ofSize: 12).descender }, getWidth: { info -> CGFloat in return 0 // 核心:返回宽度为0,不占用水平空间 }) let runDelegate = CTRunDelegateCreate(&callbacks, nil) // 添加属性 attributedString.addAttribute(.font, value: font, range: foundRange) attributedString.addAttribute(.baselineOffset, value: offsetY, range: foundRange) attributedString.addAttribute(.foregroundColor, value: color, range: foundRange) if let runDelegate = runDelegate { attributedString.addAttribute(NSAttributedString.Key(kCTRunDelegateAttributeName as String), value: runDelegate, range: foundRange) } return attributedString } }
方案2:用负字间距抵消文本宽度(无需引入CoreText)
先计算目标文本的宽度,给目标文本末尾添加负的字间距,抵消掉这段文本的宽度,也能实现不挤压效果,实现更简单:
extension String { func setSubscriptAligned(text: String, offsetY: CGFloat = -10, font: UIFont = .systemFont(ofSize: 12), color: UIColor = .red) -> NSMutableAttributedString { let attributedString = NSMutableAttributedString(string: self) let foundRange = attributedString.mutableString.range(of: text) guard foundRange.location != NSNotFound else { return attributedString } // 计算目标文本的宽度 let textWidth = text.size(withAttributes: [.font: font]).width // 添加基础属性 attributedString.addAttribute(.font, value: font, range: foundRange) attributedString.addAttribute(.baselineOffset, value: offsetY, range: foundRange) attributedString.addAttribute(.foregroundColor, value: color, range: foundRange) // 最后一个字符添加负字间距,抵消整个文本宽度 attributedString.addAttribute(.kern, value: -textWidth, range: NSRange(location: foundRange.location + foundRange.length - 1, length: 1)) return attributedString } }
注意事项
- 如果需要对齐的文本长度和上方文本长度不同,可自行调整
offsetY和添加少量水平偏移调整对齐位置 - 若涉及大量此类标注需求,建议使用TextKit自定义布局管理器实现,性能更优
你之前的实现效果参考:
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

