如何将通用的SwiftUI视图添加到另一个视图中?

3
尝试使用泛型类型来初始化/添加到另一个SwiftUI视图时,会出现错误“Type 'T' has no member 'init'”。如何解决这个问题?我猜问题在于View只是需要一个body属性而已,没有其他限制。但是应该使用什么类型呢?
简单的例子: 尝试使用TrippleView,它应该创建/显示三个类型为T的视图,添加视图(RedRectView或BlueCircleView)没有问题。但将这些视图作为泛型参数传递失败了。
struct SomeView: View {
    var body: some View {
        TrippleView<RedRectView>()
        TrippleView<BlueCircleView>()
    }
}

struct TrippleView<T: View>: View {
    var body: some View {
        VStack {
            // Does NOT work: Type 'T' has no member 'init'
            T()
            T()
            T()
            
            // Works fine
            // RedRectView()
            // BlueCircleView()
            // RedRectView()
        }
    }
}

struct RedRectView: View {...}
struct BlueCircleView: View {...}

编辑:

TrippleView 只是一个示例。我想像其他通用类型一样使用通用视图:在不同的场景下,它们都可以作为共同的基础“类型”。

例如,两个版本的列表视图,它们使用通用的 CellView 在两种不同的样式/布局中显示相同的数据。


1
你实际上想要实现什么?是自动创建三个给定视图实例并排列它们,还是其他什么? - jrturton
我已经编辑了问题以指出这一点。 - Andrei Herford
1
如果编译器只知道 T 符合 View 协议,而 View 协议又没有声明该初始化程序,那么你如何期望 T() 起作用呢?你需要创建自己的协议,符合 View,并在其中声明你想要的初始化程序,然后您可以将其用作 T 的要求,并且您会知道您的视图可以通过这种方式初始化。 - EmilioPelaez
我不确定你的示例是如何工作的 - 没有特定的初始化程序,您将无法显示任何数据。看起来你想重新发明视图构建器?如果你真的想继续使用这个方法,你需要声明一个额外的协议,其中包含你期望符合条件的视图所拥有的任何初始化程序 - 你不能只说“它是一个View”然后就此结束。 - jrturton
1个回答

5

你需要在你的结构体中使用ViewBuilder来初始化视图。以下是一个例子,

接收通用视图并返回视图的结构体。

struct TripleView<T: View>: View {
// simple example that takes in one parameter.
var someView: T

init(@ViewBuilder someView: () -> T) {
    self.someView = someView()
}

var body: some View {
    // You can modify your viewes here. 
    someView
        .foregroundColor(.red)
    someView
        .foregroundColor(.blue)
    someView
        .foregroundColor(.green)
    }
}

或者您可以接受多个参数

struct TripleViewsWithParam<T1: View, T2: View, T3: View>: View {
// you can take as many parameters as you want.
var someView1: T1
var someView2: T2
var someView3: T3

init(@ViewBuilder someView1: () -> T1, @ViewBuilder someView2: () -> T2, @ViewBuilder someView3: () -> T3) {
    self.someView1 = someView1()
    self.someView2 = someView2()
    self.someView3 = someView3()
}

var body: some View {
    VStack {
        someView1
        someView2
        someView3
    }
}
}

在您的主视图中调用结构体

struct SomeView: View {
var body: some View {
    VStack{
        TripleView {
            Text("Triple View Example")
        }
        TripleViewsWithParam(
            someView1: {
                Text("View 1")
            }, someView2: {
                Text("View 2")
            }, someView3: {
                Text("View 3")
            }
        )
    }

}
}

The result


感谢您提供的出色示例和解释。这使得事情更加清晰明了。 - Andrei Herford
我发现了这个解决方案的一个(可能的)限制,并为此添加了一个新问题: https://stackoverflow.com/q/73571940/777861 - Andrei Herford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接