我有日志视图。 我想以交替的背景颜色显示日志行。 我想允许在整个日志视图中进行文本选择。这可以在单个
.textSelection(.enabled)
视图上使用 Text
来完成。
然而,问题是,为了获得交替的颜色,我将字符串分成几行,并以
ScrollView
(或 List
)显示它们。当我添加 .textSelection(.enabled)
时,我一次只能选择一行中的文本。
我怎样才能选择整个文本。
这是代码:
struct LogView: View {
let lines: [String] = sampleText3.components(separatedBy: "\n")
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0) {
ForEach(lines.indices, id: \.self) { index in
HStack() {
Text(lines[index])
.foregroundColor(adaptiveLineColor(lines[index]))
.padding(.horizontal, 5)
Spacer()
}
.background(index % 2 == 0 ? Color.gray.opacity(0.1) : Color.black.opacity(0.1))
}
}
.textSelection(.enabled)
.border(.gray.opacity(0.1),width: 1)
}
.padding()
}
func adaptiveLineColor(_ line: String) -> Color {
enum Tag: String {
case task = "[Task]"
case info = "[info]"
case warning = "[warning]"
case error = "[error]"
}
// TODO: Use switch
if line.hasPrefix(Tag.task.rawValue) {
return .green
}
if line.hasPrefix(Tag.info.rawValue) {
return .primary
}
if line.hasPrefix(Tag.warning.rawValue) {
return .yellow
}
if line.hasPrefix(Tag.error.rawValue) {
return .red
}
return .primary
}
}
let sampleText3: String = """
[Task] Process started. 30. Sep 2023, 21:26:20
[info] input file /someFolder/someData
[warning] invalid metadata
[error] error -1234
"""
截图:
如果我将整个文本放在一个多行中
Text
,textSelection
会按预期工作,但我不知道如何交替背景颜色。
我该如何解决这个问题?
我找到了这个问题,但是没有解决办法。
一个非常简单的解决方案(尽管这有点黑客)是绘制两次。首先将文本绘制为许多单独的
Text
,每个都有自己的背景和透明的前景。然后,将整个字符串绘制为单个 Text
作为叠加层。然后用户可以选择叠加。
ScrollView {
let attrText = makeAttributedString(sampleText3) // add all the different foreground colors as an AttributedString
VStack(alignment: .leading, spacing: 0) {
// lay out the texts with transparent foreground and alternating backgrounds
let invisibleTexts = lines.map { Text($0).foregroundColor(.clear) }
ForEach(lines.indices, id: \.self) { index in
HStack {
invisibleTexts[index]
.padding(.horizontal, 5)
Spacer()
}
.background(index % 2 == 0 ? Color.gray.opacity(0.1) : Color.black.opacity(0.1))
}
}
.overlay {
// lay out the selectable text in the same way
HStack {
Text(attrText).textSelection(.enabled).padding(.horizontal, 5)
Spacer()
}
}
.border(.gray.opacity(0.1),width: 1)
}