在 SwiftUI 中构建递归文本视图

Build Recursive Text View in SwiftUI

我的目标是创建一个 SwiftUI 视图,它接受一个字符串并自动将该文本格式化为文本视图。使用正则表达式找到需要格式化的字符串部分,然后 returned 作为 Range。一旦将格式应用于适当的文本视图,这可用于重建字符串。由于可能有多个文本实例需要格式化,运行 格式化函数应该递归完成。

struct AttributedText: View {
    @State var text: String
    
    var body: some View {
        AttributedTextView(text: text)
    }
    
    @ViewBuilder
    private func AttributedTextView(text: String) -> some View {
        if let range = text.range(of: "[0-9]+d[0-9]+", options: .regularExpression) {
       
        //The unattributed text
        Text(text[text.startIndex..<range.lowerBound]) +
            
            //Append the attributed text
            Text(text[range]).bold() +
            
            //Search for additional instances of text that needs attribution
            AttributedTextView(text: String(text[range.upperBound..<text.endIndex]))
        
        } else {
            //If the searched text is not found, add the rest of the string to the end
            Text(text)
        }
    }

我收到错误 Cannot convert value of type 'some View' to expected argument type 'Text',建议的修复方法是将递归行更新为 AttributedTextView(text: String(text[range.upperBound..<text.endIndex])) as! Text。我应用了此修复程序,但仍然看到相同的编译器错误和相同的建议修复程序。

我尝试过的一些解决方法:

这些解决方案都不是很“敏捷”。解决这个问题的另一种方法是什么?我对 SwiftUI 有什么误解吗?

这里有几点需要澄清:

Text+ 重载仅在 Texts 之间起作用,这就是为什么它说它不能将 some View (您的 return 类型)转换为 TextText + Text == Text, Text + some View == ☠️

将 return 类型更改为 Text 对您不起作用,因为您使用的是 @ViewBuilder,移除 @ViewBuilder 即可正常工作。

为什么? @ViewBuilder 允许 SwiftUI 推迟对闭包的评估,但确保它会产生特定的视图类型(不是 AnyView ).如果您的闭包 returns either a TextImage 这很方便,但在您的情况下它总是导致 Text 不需要@ViewBuilder 强制 return 类型为 ConditionalContent<Text, Text> 以便 可以 有不同的类型。

这是应该起作用的:

private static func attributedTextView(text: String) -> Text {
    if let range = text.range(of: "[0-9]+d[0-9]+", options: .regularExpression) {

    //The unattributed text
    return Text(text[text.startIndex..<range.lowerBound]) +

        //Append the attributed text
        Text(text[range]).bold() +

        //Search for additional instances of text that needs attribution
        AttributedTextView(text: String(text[range.upperBound..<text.endIndex]))

    } else {
        //If the searched text is not found, add the rest of the string to the end
        return Text(text)
    }
}

我也将它设为静态,因为这里没有状态,它是一个纯函数并将其小写,所以很明显它是一个函数而不是一个类型(函数名称看起来像一个 View 类型)。

你就叫它 Self.attributedTextView(text: ...)