SwiftUI实现文本逐行高亮(非整文本框)及背景内边距设置
SwiftUI 实现文本逐行高亮效果
需求说明
需要实现文本逐行单独高亮的效果(而非高亮整个文本框),暂未找到最优方案,曾尝试复用文本变量、添加背景色、缩小字体制造间距并将文本设为透明的思路,当前使用SwiftUI,寻求可行实现方案。
当前用于文本对齐的代码如下:
struct LabelAlignment: UIViewRepresentable { var text: String var textAlignmentStyle : TextAlignmentStyle var width: CGFloat var fontName: String var fontSize: CGFloat var fontColor: UIColor func makeUIView(context: Context) -> UILabel { let font = UIFont(name: fontName, size: fontSize) let label = UILabel() label.textAlignment = NSTextAlignment(rawValue: textAlignmentStyle.rawValue)! label.numberOfLines = 0 label.preferredMaxLayoutWidth = width label.font = font label.setContentHuggingPriority(.required, for: .horizontal) label.setContentHuggingPriority(.required, for: .vertical) label.textColor = fontColor return label } func updateUIView(_ uiView: UILabel, context: Context) { uiView.text = text } } enum TextAlignmentStyle : Int{ case left = 0 ,center = 1 , right = 2 ,justified = 3 ,natural = 4 }
预期效果
预期每行文本带有独立背景高亮,效果如下:
实现方案
基于你现有的UIViewRepresentable封装逻辑,通过NSAttributedString结合文本排版计算,为每行文本添加背景色属性,具体实现如下:
1. 修改LabelAlignment组件,添加逐行高亮逻辑
struct LabelAlignment: UIViewRepresentable { var text: String var textAlignmentStyle: TextAlignmentStyle var width: CGFloat var fontName: String var fontSize: CGFloat var fontColor: UIColor var highlightColor: UIColor // 新增高亮色参数 func makeUIView(context: Context) -> UILabel { let font = UIFont(name: fontName, size: fontSize) ?? UIFont.systemFont(ofSize: fontSize) let label = UILabel() label.textAlignment = NSTextAlignment(rawValue: textAlignmentStyle.rawValue)! label.numberOfLines = 0 label.preferredMaxLayoutWidth = width label.font = font label.setContentHuggingPriority(.required, for: .horizontal) label.setContentHuggingPriority(.required, for: .vertical) label.textColor = fontColor return label } func updateUIView(_ uiView: UILabel, context: Context) { let attributedText = NSMutableAttributedString(string: text) let font = uiView.font ?? UIFont.systemFont(ofSize: fontSize) // 设置基础文本属性 attributedText.addAttribute(.font, value: font, range: NSRange(location: 0, length: attributedText.length)) attributedText.addAttribute(.foregroundColor, value: fontColor, range: NSRange(location: 0, length: attributedText.length)) // 计算每行文本范围 let layoutManager = NSLayoutManager() let textContainer = NSTextContainer(size: CGSize(width: width, height: .greatestFiniteMagnitude)) let textStorage = NSTextStorage(attributedString: attributedText) layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) textContainer.lineFragmentPadding = 0 textContainer.maximumNumberOfLines = 0 textContainer.lineBreakMode = uiView.lineBreakMode var lineRange = NSRange() var index = 0 while index < textStorage.length { // 获取当前行范围 layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange) // 为当前行添加高亮背景色 attributedText.addAttribute(.backgroundColor, value: highlightColor, range: lineRange) index = NSMaxRange(lineRange) } uiView.attributedText = attributedText } } enum TextAlignmentStyle: Int { case left = 0, center = 1, right = 2, justified = 3, natural = 4 }
2. SwiftUI视图中调用示例
struct ContentView: View { var body: some View { LabelAlignment( text: "这是一段测试文本,用于展示逐行高亮的效果。当文本内容超过一行时,每一行都会带有独立的背景高亮,而不是整个文本框统一高亮。", textAlignmentStyle: .left, width: 300, fontName: "PingFangSC-Regular", fontSize: 16, fontColor: .black, highlightColor: UIColor.yellow.withAlphaComponent(0.3) ) .padding() } }
方案优势
- 基于现有封装逻辑扩展,无需重构原有代码
- 通过NSLayoutManager精准计算每行范围,高亮效果准确
- 支持自定义高亮颜色、透明度,适配所有文本对齐方式
内容的提问来源于stack exchange,提问作者za.ch
相关产品推荐
相关产品推荐

