You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何为Text视图的选中文本自定义高亮样式?

自定义SwiftUI文本选中高亮样式

问题描述

在VStack中使用多个Text视图展示不同颜色的文本,已启用textSelection(.enabled)支持选中文本复制,但无法将自定义的带圆角蓝色半透明背景设置为选中文本的高亮样式,现有代码如下:

var body: some View {
    VStack(alignment: .leading, spacing: 0) {
        Spacer()
        ForEach(logMessages, id: \.id) { message in
            messageText(message)
        }
        Spacer()
    }
    .edgesIgnoringSafeArea(.all)
    .padding()
}

private func messageText(_ message: LogMessage) -> some View {
    return
        Text("\(message.levelString): \(message.message)")
            .font(.system(size: fontSize))
            .frame(maxWidth: .infinity, alignment: .leading)
            .foregroundColor(logColor(message.level.rawValue))
            .textSelection(.enabled)
    //                .background( // meant to be for highlighting selected text
    //                    RoundedRectangle(cornerRadius: 4)
    //                        .foregroundColor(.blue)
    //                        .opacity(0.3)
    //                )
}

解决方案

SwiftUI原生Text的文本选中样式没有公开API支持自定义,需借助UIKit的UITextView来实现自定义高亮效果,步骤如下:

1. 自定义UITextView子类

重写布局方法,给选中区域添加圆角:

class CustomSelectionTextView: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        // 遍历选中视图,设置圆角
        for subview in subviews {
            if let textSelectionView = subview as? UITextSelectionView {
                textSelectionView.subviews.forEach {
                    $0.layer.cornerRadius = 4
                    $0.layer.masksToBounds = true
                }
            }
        }
    }
    
    override var selectedTextRange: UITextRange? {
        didSet {
            setNeedsLayout()
        }
    }
}

2. 实现UIViewRepresentable桥接SwiftUI

将自定义UITextView包装成SwiftUI可识别的视图,设置选中背景色并传递富文本内容:

struct CustomSelectableText: UIViewRepresentable {
    var attributedString: NSAttributedString
    
    func makeUIView(context: Context) -> CustomSelectionTextView {
        let textView = CustomSelectionTextView()
        textView.attributedText = attributedString
        textView.isEditable = false
        textView.isSelectable = true
        textView.backgroundColor = .clear
        // 设置选中背景的半透明蓝色
        textView.selectedTextBackgroundColor = UIColor.blue.withAlphaComponent(0.3)
        textView.textContainerInset = .zero
        textView.textContainer.lineFragmentPadding = 0
        return textView
    }
    
    func updateUIView(_ uiView: CustomSelectionTextView, context: Context) {
        uiView.attributedText = attributedString
    }
}

3. 替换原Text视图

将原来的Text替换为自定义的CustomSelectableText,通过NSAttributedString设置文本颜色和字体:

private func messageText(_ message: LogMessage) -> some View {
    // 构建富文本,设置字体和文本颜色
    let attributedString = NSMutableAttributedString(string: "\(message.levelString): \(message.message)")
    let fullRange = NSRange(location: 0, length: attributedString.length)
    attributedString.addAttribute(.font, 
                                  value: UIFont.systemFont(ofSize: fontSize), 
                                  range: fullRange)
    attributedString.addAttribute(.foregroundColor, 
                                  value: UIColor(logColor(message.level.rawValue)), 
                                  range: fullRange)
    
    return CustomSelectableText(attributedString: attributedString)
        .frame(maxWidth: .infinity, alignment: .leading)
}

说明

  • 该方案通过UIKit桥接实现自定义选中样式,完美支持带圆角的半透明蓝色高亮
  • 保留了原有的文本颜色、字体样式,同时支持文本选中复制功能

内容的提问来源于stack exchange,提问作者Simon Lemcke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:02:53