具有交替行颜色的多行文本(日志视图)。如何在所有行中选择文本?

Multiple lines of text with alternating row colors (a Log view). How to select text across all lines?

提问人:soundflix 提问时间:10/1/2023 最后编辑:soundflix 更新时间:10/7/2023 访问量:55

问:

我有一个日志视图。 我想以交替的背景颜色显示日志行。 我想允许在整个日志视图中选择文本。这可以在单个视图上完成。.textSelection(.enabled)Text

然而,我的问题是,为了获得交替的背景颜色,我将字符串分成几行并将它们显示在(或)中。当我添加时,我一次只能选择一行中的文本。ScrollViewList.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
"""

截图:

enter image description here

如果我把整个文本放在一个多行中,可以按预期工作,但我不知道如何交替使用背景颜色。TexttextSelection

我该如何解决这个问题?

我找到了这个问题,但它没有解决方案。

文本选择 swiftui-text

评论

0赞 Benzy Neez 10/1/2023
如果要选择所有文本而不仅仅是部分文本,则可以提供一个按钮来共享(上传)显示的内容。
0赞 soundflix 10/1/2023
是的,导出整个日志的按钮,如 ,是我会考虑作为替代方案的东西。ShareLink

答:

1赞 Sweeper 10/1/2023 #1

一个非常简单的解决方案(尽管这有点黑客)是绘制两次。首先将文本绘制为许多单独的 s,每个 s 都有自己的背景,并带有透明的前景。然后,将整个字符串绘制为单个作为叠加层。然后,用户可以选择叠加层。TextText

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)
}

评论

0赞 soundflix 10/1/2023
非常感谢,这有效!当你说它是黑客时,你认为它有缺点吗?
0赞 Sweeper 10/1/2023
@soundflix我正在创建许多不可见的 s,其唯一目的是显示背景颜色。这相当浪费,不是吗?“非黑客”是指 SwiftUI 有一个专用的 API 来将不同视图中的文本“连接”在一起。不过我不知道这样的事情。Text
0赞 soundflix 10/1/2023
好的,我明白了;对于较长的日志,我注意到调整窗口大小时性能下降。
0赞 soundflix 10/1/2023
我现在正在用一个真实的日志进行测试,他们有空行。这些似乎在叠加层上增加了偏移量。当我在覆盖层内部添加时,它会固定到第一个空行。然后,每条空线增加大约 1 个偏移点。.offset(y: -6)
0赞 Sweeper 10/1/2023
@soundflix嗯,我没想到会这样。我以为会具有与多行文本相同的布局。我建议首先尝试做并玩弄不起作用的属性字符串的行距。TextVStackVStack(spacing:0)