【发布时间】: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 视图,我想保持灵活性,因为Apple 和Banana 以及它们上面的详细视图最终会有所不同。此外,我可能想稍后添加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)
}
}
【问题讨论】: