gpt4 book ai didi

swift - 需要在没有样板的协议(protocol)中使用 SwitftUI View

转载 作者:行者123 更新时间:2023-11-30 10:35:57 25 4
gpt4 key购买 nike

[ Ed:一旦我解决了这个问题,我编辑了这个问题的标题以更好地反射(reflect)我实际需要的内容。 - 直到我回答了自己的问题,我才澄清了我需要什么:-)]

我正在 IOS 上使用 SwiftUI 开发一个应用程序,在 6 种情况下,我将有一个可以选择的项目列表,并且在所有情况下,操作都是移动到显示该项目的屏幕。

我是一个热衷于“DRY”的倡导者,因此我不想将列表代码编写 6 次,而是想抽象出列表并选择代码,并且对于 6 个场景中的每一个场景,我只想提供该实例所独有的内容。

我想使用协议(protocol),但希望将样板代码保持在最低限度。

我的协议(protocol)和相关支持是这样的:

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)")
}
}

因为这是独一无二的。但这肯定不会编译。

然后对于详细信息也是如此。

我不知道如何进一步简化。欢迎任何想法吗?

最佳答案

关键是,如果您想在协议(protocol)中使用 View ,那么:

1)在协议(protocol)中:

  associatedtype SpecialView: View
var specialView: SpecialView { get }

2)在使用协议(protocol)的结构中:

  var specialView: some View { Text("Special View") }

所以在问题的情况下:

通过将我的协议(protocol)更改为:

protocol ListAndSelectItem: Identifiable {
var name: String { get set }
var value: Int { get set }

// For listView:
static var listTitle: String { get }
associatedtype ListView: View
var listView: ListView { get }

// For detailView:
var detailTitle: String { get }
associatedtype DetailView: View
var detailView: DetailView { get }
}

我现在可以将 Person 定义为:

struct Person: ListAndSelectItem {
var id = UUID()
var name: String
var value: Int

static var listTitle = "People"
var listView: some View { Text("List View for \(name)") }

var detailTitle = "Person"
var detailView: some View { Text("Detail View for \(name)") }
}

适合 DRY 并且没有样板!

关于swift - 需要在没有样板的协议(protocol)中使用 SwitftUI View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58034739/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com