#100DaysOfSwiftUI Day60 Challengeをやってみる (Step3 : ユーザー詳細画面実装)

メインウィンドウにユーザーをリスト表示することができるようになったので、詳細画面を作ります。

手順は、以下の通り

  • DetailViewの大枠作る
  • NavigationLink作る
  • DetailViewの作り込み
  • Refactoring

DetailViewを作る

UserDetailViewという名前でViewを作りました。
このビューは、Userを受け取って表示するはずなので、まずは、Userを持つようにしました。
また、Previewを見るためには、以前、メインビューのPreview用にUserのinitializerを利用しました。(少しアップデートしてます)

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

NavigationLinkを作る

ContentView.swiftの方に戻って、各Userの行をNavigationLinkにしていきます。

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を作り込む

適当に(?)作りました。

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のコードです。

required init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    let tagName = try container.decode(String.self)
    name = tagName
}

Encodeも気を付けないといけません。(今回のケースでは使われません)

func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    try container.encode(name)
}

せっかくなので、DetailViewにTagを表示するListも追加しました

Tag読み込みに苦労したので、DetailViewにTagを表示するListを追加しました。

あわせて、Sectionにタイトルをつけています。このあたりは、凝り始めるとエンドレスだと思うので、これくらいにしておきます。

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の表示
Day60DataLoadedMoreImproved

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です