问题
I'm trying to work through understanding how I can make data flow nicely through an app I'm building. I just want a basic master detail view where it starts with a list of all the top level objects(users), tapping one of them lets you see all the second level objects related to that top level (userX -> cities), and tapping one of them lets you see all the third level objects (userX -> cityX -> towns).
This is my JSON file:
[
{
"id": 1001,
"first_name": "Jimmy",
"last_name": "Simms",
"cities": [{
"name": "New York City",
"towns": [{
"name": "Brooklyn"
},
{
"name": "Manhatten"
}
]
},
{
"name": "Tokyo",
"towns": [{
"name": "Churo"
},
{
"name": "Riponggi"
}
]
}
]
}
...
]
I have a model that I think will work well for this:
import SwiftUI
struct UserModel: Codable, Identifiable {
let id: Int
let firstName: String
let lastName: String
let cities: [CityModel]
enum CodingKeys: String, CodingKey {
case id
case firstName = "first_name"
case lastName = "last_name"
case cities
}
}
struct CityModel: Codable {
let name: String
let towns: [TownModel]
}
struct TownModel: Codable {
let name: String
}
However, what I'm struggling to do is to build this all into a series of list views that are connected to each other. I have the top level one, UserList.swift at least showing a list of the users.
import SwiftUI
struct UserList: View {
var body: some View {
NavigationView {
List(userData) { user in
NavigationLink(destination: UserRow(user: user)) {
UserRow(user: user)
}
}
.navigationBarTitle(Text("Users"))
}
}
}
struct UserList_Previews: PreviewProvider {
static var previews: some View {
UserList()
}
}
And it's assistant view, UserRow:
import SwiftUI
struct UserRow: View {
var user: UserModel
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(user.firstName)
.font(.headline)
Text(user.lastName)
.font(.body)
.foregroundColor(Color.gray)
}
Spacer()
}
}
}
struct UserRow_Previews: PreviewProvider {
static var previews: some View {
UserRow(user: userData[0])
}
}
UserList.swift Preview:
What I can't figure out is how to write CityList/CityRow and TownList/TownRow such that I can drill down from the main screen and get a list related to the objected I tapped into.
回答1:
Your CityModel and TownModel need to conform to Identifiable, just add an id to them like you did in UserModel.
Than you need to edit your UserList NavigationLink:
NavigationLink(destination: CityList(cities: user.cities)) {
Text(user.firstName)
}
The Navigation is now like this: UserList -> CityList -> TownList
CityList:
struct CityList: View {
var cities: [CityModel]
var body: some View {
List (cities) { city in
NavigationLink(destination: TownList(towns: city.towns)) {
Text(city.name)
}
}
}
}
TownList:
struct TownList: View {
var towns: [TownModel]
var body: some View {
List (towns) { town in
Text(town.name)
}
}
}
I hope that helps, in my test project it works!
回答2:
first you have to create CityListView and CityRow, like you did for users:
struct CityListView: View {
var user: UserModel
var body: some View {
// don't forget to make CityModel Identifiable
List(user.cities) { city in
CityRowView(city: city)
}
.navigationBarTitle(Text("Cities"))
}
}
}
struct CityRowView: View {
var city: CityModel
var body: some View {
HStack {
Text(city. name)
.font(.headline)
Spacer()
}
}
}
after that you need to change destination in NavigationLink (not UserRow, but new CityListView)
...
//NavigationLink(destination: UserRow(user: user)) {
NavigationLink(destination: CityListView(user: user)) {
UserRow(user: user)
}
...
Another way is to declare variable "cities" as an array of CityModel and receive it from user:
struct CityListView: View {
var cities: [UserModel]
// list for array of cities
}
// in UserList
NavigationLink(destination: CityListView(cities: user.cities)) {
UserRow(user: user)
}
P.S. Apple made excellent tutorial for navigations in SwiftUI: https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
来源:https://stackoverflow.com/questions/58635853/creating-a-series-of-master-detail-lists-from-a-single-json-file-in-swiftui