Требуется представление SwitftUI в протоколе без шаблона - PullRequest
0 голосов
/ 20 сентября 2019

[Эд: Как только я решил это, я отредактировал название этого вопроса, чтобы лучше отразить то, что мне действительно нужно.- только когда я ответил на свой вопрос, я объяснил, что мне нужно :-)]

Я занимаюсь разработкой приложения с использованием 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)")
  }
}

, потому что это уникальный бит.Но это, конечно, не скомпилируется.

И то же самое с деталями.

Я не могу понять, как упростить дальнейшее.Любые идеи приветствуются?

1 Ответ

0 голосов
/ 23 сентября 2019

Ключ к этому заключается в том, что если вы хотите использовать представление в протоколе, то:

1) В протоколе:

  associatedtype SpecialView: View
  var specialView: SpecialView { get }

2) В структуре с использованием протокола:

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

Итак, в ситуации вопроса:

Изменяя мой протокол на:

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

который подходит СУХОЙ и не содержит образцов!

...