SwiftUI:NavigationLink的目标视图的异构集合吗?

时间:2019-07-25 17:03:58

标签: ios swiftui

我正在构建类似不同示例的演示应用程序,并且我希望根视图为List,可以导航到不同示例视图。因此,我尝试创建一个通用的Example结构,该结构可以采用不同的目的地View,如下所示:

struct Example<Destination: View> {
    let id: UUID
    let title: String
    let destination: Destination

    init(title: String, destination: Destination) {
        self.id = UUID()
        self.title = title
        self.destination = destination

    }
}

struct Example1View: View {
    var body: some View {
        Text("Example 1!")
    }
}

struct Example2View: View {
    var body: some View {
        Text("Example 2!")
    }
}

struct ContentView: View {
    let examples = [
        Example(title: "Example 1", destination: Example1View()),
        Example(title: "Example 2", destination: Example2View())
    ]

    var body: some View {
        List(examples, id: \.id) { example in
            NavigationLink(destination: example.destination) {
                Text(example.title)
            }
        }
    }
}

不幸的是,这会导致错误,因为examples是一个异构集合:

enter image description here

我完全理解为什么这被打破了;我要创建一个示例数组,因为每个Example结构都有自己不同的强类型目标。但是我不知道如何实现自己想要的目标,我可以创建一个List数组,其中有多个不同的允许目标。

过去,我遇到过这种情况,过去我通过包装我的泛型类型并只暴露我需要的确切属性来解决它(例如,如果我有一个具有标题,我将制作只暴露标题的包装器结构和协议,然后制作该包装器结构的数组)。但是在这种情况下,NavigationLink本身必须具有通用类型,因此没有一个属性只能以非通用方式公开给它。

1 个答案:

答案 0 :(得分:3)

您可以使用类型擦除的包装器AnyView。构造Example时,不要使AnyView成为通用视图,而应将其中的目标视图设为AnyView类型,并将视图包装在Example中。

例如:

struct Example {

    let id: UUID
    let title: String
    let destination: AnyView

    init(title: String, destination: AnyView) {
        self.id = UUID()
        self.title = title
        self.destination = destination
    }
}

struct Example1View: View {
    var body: some View {
        Text("Example 1!")
    }
}

struct Example2View: View {
    var body: some View {
        Text("Example 2!")
    }
}

struct ContentView: View {
    let examples = [
        Example(title: "Example 1", destination: AnyView(Example1View())),
        Example(title: "Example 2", destination: AnyView(Example2View()))
    ]

    var body: some View {
        NavigationView {
            List(examples, id: \.id) { example in
                NavigationLink(destination: example.destination) {
                    Text(example.title)
                }
            }
        }
    }
}