【问题标题】:Passing views, or higher-order components, in SwiftUI在 SwiftUI 中传递视图或高阶组件
【发布时间】:2020-08-09 17:21:04
【问题描述】:

作为一个了解 React 的人,来到 SwiftUI 之后,我在寻找合适的抽象方面遇到了挑战。这是一个例子,但我的问题更笼统。它与传递视图或 React 社区所称的高阶组件有关。我的例子如下。 TLDR:如何在下面的列表视图中抽象和删除重复项?

一些模型(这些最终会有所不同):

struct Apple: Comparable, Identifiable {
    let id: UUID = UUID()
    let label: String

    static func < (lhs: Apple, rhs: Apple) -> Bool {
        lhs.label < rhs.label
    }
}

struct Banana: Comparable, Identifiable {
    let id: UUID = UUID()
    let label: String

    static func < (lhs: Banana, rhs: Banana) -> Bool {
        lhs.label < rhs.label
    }
}

一些基本的细节视图(这些最终会有所不同):

struct AppleView: View {
    let apple: Apple

    var body: some View {
        Text(apple.label)
    }
}

struct BananaView: View {
    let banana: Banana

    var body: some View {
        Text(banana.label)
    }
}

还有两个有很多重复的列表视图:

struct AppleListView: View {
    let title: String
    let apples: [Apple]

    var body: some View {
        List(apples.sorted()) { apple in
            NavigationLink(destination: AppleView(apple: apple)) {
                Text(apple.label)
                    .padding(.all)
            }
        }
        .navigationBarTitle(Text(title), displayMode: .inline)
    }
}

struct BananaListView: View {
    let title: String
    let bananas: [Banana]

    var body: some View {
        List(bananas.sorted()) { banana in
            NavigationLink(destination: BananaView(banana: banana))
                Text(banana.label)
                    .padding(.all)
            }
        }
        .navigationBarTitle(Text(title), displayMode: .inline)
    }
}

如您所见,它仅在很小的部分上有所不同。集合的类型和destination 视图不同。对于destination 视图,我想保持灵活性,因为AppleBanana 以及它们上面的详细视图最终会有所不同。此外,我可能想稍后添加Cherry,因此抽象此列表视图很有价值。

所以,我的问题是:我怎样才能最好地抽象上面的列表视图并删除其中的重复项?你有什么建议?我的尝试如下,但它给我留下了类型错误。它涉及前面提到的高阶组件思想。

我的类型错误尝试:

struct AppleListView: View {
    let title: String
    let apples: [Apple]

    var body: some View {
        ListView(
            title: title,
            rows: apples, // it complains about types here -> `Cannot convert value of type '[Apple]' to expected argument type 'Array<_>'`
            rowView: { apple in Text(apple.label) },
            destinationView: { apple in AppleView(apple: apple) }
        )
    }
}

struct BananaListView: View {
    let title: String
    let bananas: [Banana]

    var body: some View {
        ListView(
            title: title,
            rows: bananas, // it complains about types here -> `Cannot convert value of type '[Banana]' to expected argument type 'Array<_>'`
            rowView: { banana in Text(banana.label) },
            destinationView: { banana in BananaView(banana: banana) }
        )
    }
}

struct ListView<Content: View, Row: Comparable & Identifiable>: View {
    let title: String
    let rows: [Row]
    let rowView: (Row) -> Content
    let destinationView: (Row) -> Content

    var body: some View {
        List(rows.sorted()) { row in
            NavigationLink(destination: self.destinationView(row)) {
                self.rowView(row)
                    .padding(.all)
            }
        }
        .navigationBarTitle(Text(title), displayMode: .inline)
    }
}

【问题讨论】:

    标签: ios swift reactjs swiftui


    【解决方案1】:

    这是因为你为标签和目的地设置了相同的类型,这里是固定的变体

    struct ListView<Target: View, Label: View, Row: Comparable & Identifiable>: View {
        let title: String
        let rows: [Row]
        let rowView: (Row) -> Label
        let destinationView: (Row) -> Target
    
        var body: some View {
            List(rows.sorted()) { row in
                NavigationLink(destination: self.destinationView(row)) {
                    self.rowView(row)
                        .padding(.all)
                }
            }
            .navigationBarTitle(Text(title), displayMode: .inline)
        }
    }
    

    【讨论】:

    • 谢谢!为什么rowViewdestinationView 不能有相同的类型?
    • @kodnin,它们可以,但也可以不同,如您的情况 - 标签是文本,但目标是 BananaView 或 AppleView。所以泛型应该声明泛型变体的可能性,即。不同的类型。
    • 好的!所以不能推断AppleViewBananaView 也返回Text,就像rowView 一样?
    猜你喜欢
    • 2019-05-18
    • 2020-01-01
    • 2020-07-30
    • 2017-11-25
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多