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
相关产品推荐
相关产品推荐

