Created
August 4, 2019 13:26
-
-
Save PaulWoodIII/914018cfdbb0ed23dfa5fccd508b740c to your computer and use it in GitHub Desktop.
How to solve rendering a Heterogeneous collection when you are required to use a Homogeneous List of Objects in SwiftUI, In short use a Wrapper / Box around the content
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // ListOfAnimals.swift | |
| // AnimalList | |
| // | |
| // Created by Paul Wood on 8/4/19. | |
| // Copyright © 2019 Paul Wood. All rights reserved. | |
| // | |
| import SwiftUI | |
| protocol Animal { | |
| var displayName: String { get } | |
| var action: () -> () { get } // a closure that does some work | |
| } | |
| struct Dog: Animal { | |
| private var name: String | |
| var displayName: String { | |
| return "I'm a Good Dog named: \(name)" | |
| } | |
| var action: () -> () { | |
| get { | |
| return self.bark | |
| } | |
| } | |
| init(_ value: String) { | |
| self.name = value | |
| } | |
| func bark() { | |
| print("bark") | |
| } | |
| } | |
| struct Cat: Animal { | |
| var name: String | |
| var displayName: String { | |
| return "I'm the best Cat named: \(name)" | |
| } | |
| var action: () -> () { | |
| get { | |
| return self.meow | |
| } | |
| } | |
| init(_ value: String) { | |
| self.name = value | |
| } | |
| func meow() { | |
| print("meow") | |
| } | |
| } | |
| struct Bat { | |
| var name: String = "Dracula" | |
| func scaryNoises() { | |
| print("Muahahahahah am I really an Animal? No I'm Dracula") | |
| } | |
| } | |
| //: Wrapper around the specialized name types above | |
| //: We know how this type will be used so now it conforms to Identifiable | |
| //: instead of the models above | |
| struct AnimalHolder: Animal, Identifiable { | |
| var id: UUID | |
| var displayName: String | |
| var action: () -> () | |
| init<U>(nameable name: U) where U: Animal { | |
| self.displayName = name.displayName | |
| self.action = name.action | |
| self.id = UUID() | |
| } | |
| init(bat: Bat) { | |
| self.displayName = "I'm a bat" | |
| self.action = bat.scaryNoises | |
| self.id = UUID() | |
| } | |
| } | |
| let animals: [AnimalHolder] = [ | |
| AnimalHolder(nameable: Dog("Alice")), | |
| AnimalHolder(nameable: Dog("Bob")), | |
| AnimalHolder(nameable: Cat("Clark")), | |
| AnimalHolder(nameable: Cat("Davis")), | |
| AnimalHolder(nameable: Dog("Elanore")), | |
| AnimalHolder(nameable: Dog("Frank")), | |
| AnimalHolder(nameable: Cat("Gonzalez")), | |
| AnimalHolder(nameable: Cat("Harris")), | |
| AnimalHolder(nameable: Cat("Harris")), //Can Duplicate | |
| AnimalHolder(nameable: Dog("Harris")), // Can go across types | |
| AnimalHolder(bat: Bat()) | |
| ] | |
| struct AnimalDetail: View { | |
| var animal: AnimalHolder | |
| var body: some View { | |
| VStack { | |
| Spacer() | |
| Text("Animal").font(.title) | |
| Text(animal.displayName).font(.body) | |
| Button(action: { | |
| print("play pressed") | |
| self.animal.action() | |
| }, label: { | |
| Image(systemName: "play") | |
| Text("Make My Noise") | |
| }) | |
| .foregroundColor(Color.white) | |
| .padding() | |
| .background(Color.blue) | |
| .cornerRadius(5) | |
| Spacer() | |
| } | |
| } | |
| } | |
| struct ListOfAnimals: View { | |
| var body: some View { | |
| NavigationView { | |
| List(animals) { animal in | |
| NavigationLink(destination: AnimalDetail(animal: animal)) { | |
| HStack { | |
| Text(animal.displayName) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| #if DEBUG | |
| struct ContentView_Previews: PreviewProvider { | |
| static var previews: some View { | |
| MultipleIdentifiableList() | |
| } | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment