[Эд: Как только я решил это, я отредактировал название этого вопроса, чтобы лучше отразить то, что мне действительно нужно.- только когда я ответил на свой вопрос, я объяснил, что мне нужно :-)]
Я занимаюсь разработкой приложения с использованием SwiftUI на IOS, в котором у меня есть 6 ситуаций, в которых у меня будетСписок элементов, которые я могу выбрать, и во всех случаях действие будет состоять в том, чтобы перейти к экрану, на котором отображается этот элемент.
Я - сторонник "СУХОГО", поэтому вместо того, чтобы писать Код списка 6 раз, я хочуабстрагируйся от списка и выбери код, и для каждого из 6 сценариев я хочу просто указать, что уникально для этого экземпляра.
Я хочу использовать протокол, но хочу свести шаблон к минимуму.
Мой протокол и связанная с ним поддержка таковы:
import SwiftUI
/// -----------------------------------------------------------------
/// ListAndSelect
/// -----------------------------------------------------------------
protocol ListAndSelectItem: Identifiable {
var name: String { get set }
var value: Int { get set }
// For listView:
static var listTitle: String { get }
associatedtype ItemListView: View
func itemListView() -> ItemListView
// For detailView:
var detailTitle: String { get }
associatedtype DetailView: View
func detailView() -> DetailView
}
extension Array where Element: ListAndSelectItem {
func listAndSelect() -> some View {
return ListView(items: self, itemName: Element.listTitle)
}
}
struct ListView<Item: ListAndSelectItem>: View {
var items: [Item]
var itemName: String
var body: some View {
NavigationView {
List(items) { item in
NavigationLink(
destination: DetailView(item: item, index: String(item.value))
) {
VStack(alignment: .leading){
item.itemListView()
.font(.system(size: 15)) // Feasible that we should remove this
}
}
}
.navigationBarTitle(Text(itemName).foregroundColor(Color.black))
}
}
}
struct DetailView<Item: ListAndSelectItem>: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var item: Item
var index: String
var body: some View {
NavigationView(){
item.detailView()
}
.navigationBarTitle(Text(item.name).foregroundColor(Color.black))
.navigationBarItems(leading: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}, label: { Text("<").foregroundColor(Color.black)}))
}
}
, что означает, что я могу просто написать:
struct Person: ListAndSelectItem {
var id = UUID()
var name: String
var value: Int
typealias ItemListView = PersonListView
static var listTitle = "People"
func itemListView() -> PersonListView {
PersonListView(person: self)
}
typealias DetailView = PersonDetailView
let detailTitle = "Detail Title"
func detailView() -> DetailView {
PersonDetailView(person: self)
}
}
struct PersonListView: View {
var person: Person
var body: some View {
Text("List View for \(person.name)")
}
}
struct PersonDetailView: View {
var person: Person
var body: some View {
Text("Detail View for \(person.name)")
}
}
struct ContentView: View {
let persons: [Person] = [
Person(name: "Jane", value: 1),
Person(name: "John", value: 2),
Person(name: "Jemima", value: 3),
]
var body: some View {
persons.listAndSelect()
}
}
, что неплохо, но я чувствую, что должен быть в состоянииидти дальше.
Необходимость писать:
typealias ItemListView = PersonListView
static var listTitle = "People"
func itemListView() -> PersonListView {
PersonListView(person: self)
}
с
struct PersonListView: View {
var person: Person
var body: some View {
Text("List View for \(person.name)")
}
}
все еще кажется мне громоздким.В каждом из моих 6 случаев я буду писать очень похожий код.Я чувствую, что должен просто написать:
static var listTitle = "People"
func itemListView() = {
Text("List View for \(name)")
}
}
, потому что это уникальный бит.Но это, конечно, не скомпилируется.
И то же самое с деталями.
Я не могу понять, как упростить дальнейшее.Любые идеи приветствуются?