如何为NSMutableAttributedString开启UILabel孤词预防功能
UILabel富文本场景下开启防孤词排版的方法
问题说明
UILabel默认自带防孤词排版特性:自动换行时如果最后一行仅剩1个单词,系统会自动将上一行的一个单词调整至最后一行,避免单个单词/字符独占一行的排版问题。
但使用NSMutableAttributedString为UILabel赋值时,该特性默认不生效。受业务限制必须使用富文本实现,无法采用双UILabel拆分的替代方案。
问题效果参考:
原有问题代码:
var string = customField?.title ?? "" if customField?.required == true { string += " *" } else { string += " (\(getLocalizedString(localizedKey: .optional)))" } let style = NSMutableParagraphStyle() if #available(iOS 14.0, *) { style.lineBreakStrategy = .standard } let att = NSMutableAttributedString(string: string, attributes: [.paragraphStyle: style]) titleLabel.attributedText = att
失效原因
原有代码存在三个容易遗漏的配置问题:
- 仅在富文本初始化时传入段落样式,若后续对富文本做追加、属性修改操作,很容易导致段落样式没有覆盖到完整文本范围,防孤词策略不生效
- 没有同步配置UILabel自身的
lineBreakStrategy属性,UILabel的默认配置会覆盖富文本内的段落样式设置 - 拼接后缀时使用普通空格,短后缀(比如
*)在排版计算时仍可能被单独挤到最后一行
正确实现方案
- 配置
NSMutableParagraphStyle的lineBreakStrategy为.standard(iOS14及以上可用,该策略默认包含防孤词排版规则,不要设置为.pushOut这类会关闭孤词保护的策略) - 同步给UILabel对象的
lineBreakStrategy属性设置相同值,避免系统默认配置覆盖富文本样式 - 富文本创建完成后,显式将段落样式添加到富文本的完整范围,避免样式覆盖问题
- 拼接短后缀(必填星号、可选文案括号)时,使用
\u{00A0}(不换行空格)替代普通空格,强制后缀和前面的相邻文本绑定,从根源上避免短后缀单独成行 - 若需要兼容iOS14以下系统,系统无公开API支持全局防孤词策略,只能通过手动插入不换行空格、调整标签宽度的方式实现排版优化
修正后的可运行代码:
var string = customField?.title ?? "" if customField?.required == true { // 不换行空格拼接必填标记,避免*被单独挤到下一行 string += "\u{00A0}*" } else { let optionalText = getLocalizedString(localizedKey: .optional) // 可选后缀同样用不换行空格连接 string += "\u{00A0}(\(optionalText))" } let style = NSMutableParagraphStyle() if #available(iOS 14.0, *) { style.lineBreakStrategy = .standard // 同步配置label本身的换行策略 titleLabel.lineBreakStrategy = .standard } let att = NSMutableAttributedString(string: string) // 显式给富文本全范围添加段落样式,避免样式覆盖 att.addAttributes([.paragraphStyle: style], range: NSRange(location: 0, length: att.length)) titleLabel.attributedText = att
内容的提问来源于stack exchange,提问作者hasan
相关产品推荐
相关产品推荐

