メインウィンドウにユーザーをリスト表示することができるようになったので、詳細画面を作ります。
手順は、以下の通り
- DetailViewの大枠作る
- NavigationLink作る
- DetailViewの作り込み
- Refactoring
目次
DetailViewを作る
UserDetailViewという名前でViewを作りました。
このビューは、Userを受け取って表示するはずなので、まずは、Userを持つようにしました。
また、Previewを見るためには、以前、メインビューのPreview用にUserのinitializerを利用しました。(少しアップデートしてます)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct UserDetailView: View { var user:User var body: some View { VStack { Text("Name : \(user.name)") } .navigationBarTitle("User Detail:") } } struct UserDetailView_Previews: PreviewProvider { static var previews: some View { UserDetailView(user: User(id: "Super Guitarist", isActive: false, name: "Michael Hedges", age: 34)) } } |
ContentView.swiftの方に戻って、各Userの行をNavigationLinkにしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
struct ContentView: View { @ObservedObject var userList: UserList var body: some View { NavigationView { List(userList.users) { user in NavigationLink(destination: UserDetailView(user: user)) { VStack (alignment: .leading) { Text("\(user.name)") HStack { Spacer() Text("age: \(user.age)") .font(.footnote) Spacer() Text("isActive: \(String(user.isActive))") .font(.footnote) Spacer() } } } } .navigationBarTitle("FriendDB") } } } |
シミュレータで、ユーザーの行をタップして、UserDetailViewに遷移することを確認します。
UserDetailViewを作り込む
適当に(?)作りました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct UserDetailView: View { var user:User var body: some View { VStack(alignment: .leading) { Text("ID : \(user.id)") .font(.footnote) Text("Name : \(user.name)") Text("age : \(user.age)") Text("company : \(user.company)") Text("Friend List") List(user.friends) { friend in Text("FriendName: \(friend.name)") } } .navigationBarTitle("User Detail:") } } |
次のステップのポイントになるのは、Friendなので、それを表示してあとは、適当です。
なお、上記のListで処理するために、Friendクラスを、IdentifiableにConformしている宣言を追加しました。(実際しています)
いそいそとテストしようとして、Tags情報がきちんと読み込まれていないことわかりました!
Codable again:(
Userの配列 <-> UserList の関係では、無名リストの扱いに気をつけなければいけませんでした。このTagのケースでは、Tagsというキーに保存されているのが、無名要素のリストであるということでした。(JSONについての経験があまりないので、少し変わった(?)構成になるとその度にハマってます。)
このTagのようなケースでは、singleValueContainerというものを使って、アクセスするようです。以下、Tagのdecodeのコードです。
1 2 3 4 5 |
required init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let tagName = try container.decode(String.self) name = tagName } |
Encodeも気を付けないといけません。(今回のケースでは使われません)
1 2 3 4 |
func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(name) } |
せっかくなので、DetailViewにTagを表示するListも追加しました
Tag読み込みに苦労したので、DetailViewにTagを表示するListを追加しました。
あわせて、Sectionにタイトルをつけています。このあたりは、凝り始めるとエンドレスだと思うので、これくらいにしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
struct UserDetailView: View { var user:User var body: some View { VStack(alignment: .leading) { Section(header: Text("General")) { Text("ID : \(user.id)") .font(.footnote) Text("Name : \(user.name)") Text("age : \(user.age)") Text("company : \(user.company)") } Section(header: Text("Tag")) { List(user.tags) { tag in Text("\(tag.name)") } } Section(header: Text("Friend")) { List(user.friends) { friend in Text("FriendName: \(friend.name)") } } } .navigationBarTitle("User Detail:") } } |
ここまでにできた、UserDetailViewの表示
Sponsor Link