SwiftUI主屏幕小组件Text使用underline()时下划线断裂如何解决
问题原因
这是WidgetKit自iOS14起就存在的渲染层系统bug:小组件运行在独立的渲染进程中,和主App的SwiftUI渲染逻辑并不完全一致,内置的.underline()修饰符在绘制下划线时,无法正确处理字偶距、字形降部(g/y/p等字母的下伸区域)、行高的计算,最终出现下划线分段断裂的表现。该问题和业务侧的参数配置无关,调整字体、字号、基线偏移都只能临时改变错位程度,无法彻底修复。
解决方案
iOS15+ 推荐方案:富文本原生渲染
直接放弃.underline()修饰符,通过AttributedString给文本设置下划线属性,该链路走CoreText底层绘制逻辑,不会出现断裂问题,且天然支持多行自动换行、动态字体、多语言字形适配,不需要手动计算任何布局参数,稳定性最高。
struct NotLoggedInSmallView: View { private var underlinedContent: AttributedString { var attrText = AttributedString("Ready to write a new chapter in travel?") attrText.underlineStyle = .single // 可按需自定义下划线颜色,默认与文字 foregroundColor 一致 // attrText.underlineColor = .accentColor return attrText } var body: some View { Text(underlinedContent) // 此处可正常添加.font/.foregroundColor等文本修饰符,不会影响下划线效果 .font(.system(size: 14)) } }
iOS14 兼容方案
iOS14的Text组件不支持直接传入AttributedString,可以通过UIViewRepresentable封装UILabel实现带下划线的文本,小组件内的静态视图封装不会产生额外性能开销,同样支持多行自适应:
struct UnderlinedText: View { private let content: String private let font: UIFont init(_ content: String, font: UIFont = .systemFont(ofSize: 14)) { self.content = content self.font = font } var body: some View { WrappedLabel(content: content, font: font) } private struct WrappedLabel: UIViewRepresentable { let content: String let font: UIFont func makeUIView(context: Context) -> UILabel { let label = UILabel() label.numberOfLines = 0 label.lineBreakMode = .byWordWrapping return label } func updateUIView(_ label: UILabel, context: Context) { label.attributedText = NSAttributedString( string: content, attributes: [ .font: font, .underlineStyle: NSUnderlineStyle.single.rawValue ] ) } } } // 调用方式 struct NotLoggedInSmallView: View { var body: some View { UnderlinedText("Ready to write a new chapter in travel?") } }
避坑提示
- 不要尝试通过调整
baselineOffset、lineSpacing等布局参数修复.underline()的断裂问题,这类调整仅能适配单一固定字号,切换动态字体、系统版本后大概率会再次出现错位 - 手动在文本下方绘制横线的方案仅适用于固定宽度的单行文本,多行场景下无法自动匹配换行后的行位置,适配成本极高,不推荐使用。
内容的提问来源于stack exchange,提问作者Kirby Todd
相关产品推荐
相关产品推荐

