#author("2021-07-29T08:38:30+00:00","default:src128","src128")
#author("2021-07-29T08:42:13+00:00","default:src128","src128")
&tag(SwiftUI/BuildingListsAndNavigation);
*目次 [#ac7c317e]
#contents
*関連ページ [#j7b818d6]
*参考情報 [#q2213c87]
-[[Building Lists and Navigation — SwiftUI Tutorials | Apple Developer Documentation:https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation]]
-CreatingAndCombiningViewsの最後のLandmarkプロジェクトをコピーして使用。
-Resourcesフォルダはダウンロードした奴を上書きしたほうが良いかも。

*Create a Landmark Model [#zd6e543b]
-データを保持するためのモデルを作成する。
-landmarkData.jsonをプロジェクトのResourcesフォルダ以下にコピー。
-New > FileでLandmark.swiftを追加。
-以下のように定義する。
#pre{{
struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
}
}}
-画像の関連付け
#pre{{
struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String

    private var imageName: String
    var image: Image {
        Image(imageName)
    }
}
}}
-coordinatesを追加。最終的に以下のように。
#pre{{
struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String

    private var imageName: String
    var image: Image {
        Image(imageName)
    }
    
    private var coordinates: Coordinates
    
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }


    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

}}
-ModelData.swiftを追加。load関数を作成する。
#pre{{
var landmarks: [Landmark] = load("landmarkData.json")

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data

    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
    }

    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }

    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }

}}
-ViewsグループにContentView.swift、CircleImage.swift、MapView.swiftを追加。ResourcesグループにlandmarkData.jsonを追加。ModelグループにLandmark.swiftとModelData.swiftを追加。

*Create the Row View [#b33d2799]
-LandmarkRow.swiftを追加。以下のように作成。
#pre{{
struct LandmarkRow: View {
    var landmark: Landmark
    
    var body: some View {
        HStack {
            landmark.image
                .resizable()
                .frame(width: 50, height: 50)
            Text(landmark.name)

            Spacer()
        }

    }
}

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkRow(landmark: landmarks[0]);
    }
}

}}
*Customize the Row Preview [#h9c2b5ac]
-プレビューの変更
#pre{{
struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkRow(landmark: landmarks[1]).previewLayout(.fixed(width: 300, height: 70))
    }
}

}}
-二つ表示
#pre{{
       Group {
            LandmarkRow(landmark: landmarks[0])
                .previewLayout(.fixed(width: 300, height: 70))
            LandmarkRow(landmark: landmarks[1])
                .previewLayout(.fixed(width: 300, height: 70))
        }

}}

*Create the List of Landmarks [#kf86c1ab]
リストビューを実装する。

-SwiftUIファイルのLandmarkList.swiftを作成。
#pre{{
struct LandmarkList: View {
    var body: some View {
        List {
            LandmarkRow(landmark: landmarks[0])
            LandmarkRow(landmark: landmarks[1])
        }
    }
}
}}


*Make the List Dynamic [#h089389e]

Listにコレクションを表示。
-LandmarkListを変更。
#pre{{
struct LandmarkList: View {
    var body: some View {
        List(landmarks, id: \.id) { landmark in
            LandmarkRow(landmark: landmark)
        }
    }

}}
-もしくはLandmarkを変更してIdentifiableを実装。これでプレビュー画面にリストが表示される。

*Set Up Navigation Between List and Detail [#i2b23d8a]
リストと詳細をナビゲートできるようにする。

-SwiftUI ViewのLandmarkDetailを追加。
-ContentViewの内容を移植。
#pre{{
struct LandmarkDetail: View {
    var body: some View {
        VStack {
            MapView()
                .ignoresSafeArea(edges: .top)
                .frame(height: 300)

            CircleImage()
                .offset(y: -130)
                .padding(.bottom, -130)

            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                    .foregroundColor(.primary)

                HStack {
                    Text("Joshua Tree National Park")
                    Spacer()
                    Text("California")
                }
                .font(.subheadline)
                .foregroundColor(.secondary)

                Divider()

                Text("About Turtle Rock")
                    .font(.title2)
                Text("Descriptive text goes here.")
            }
            .padding()

            Spacer()
        }
    }
}

}}
-ContentViewでLandmarkListを生成。
#pre{{
struct ContentView: View {
    var body: some View {
        LandmarkList()
    }
}

}}
-LandmarkListの中にNavigationViewを入れる。プレビューの上部に空白ができる。タイトルも追加。
#pre{{
struct LandmarkList: View {
    var body: some View {
        NavigationView {
            List(landmarks) { landmark in
                NavigationLink(destination: LandmarkDetail()) {
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationTitle("Landmarks")
        }
    }
}
-ライブプレビューで遷移を確認可能。

}}




*Pass Data into Child Views [#oaf4708d]
詳細ビューにデータを引き渡す。

-CircleImageでimageを格納する。
#pre{{
struct CircleImage: View {
    var image: Image
    var body: some View {
        image
            .clipShape(Circle())
            .overlay(Circle().stroke(Color.white, lineWidth: 4))
            .shadow(radius: 7)
    }
}


struct CircleImage_Previews: PreviewProvider {
    static var previews: some View {
        CircleImage(image: Image("turtlerock"))
    }
}
}}
-MapViewにcoordinateプロパティを追加。
#pre{{
struct MapView: View {
    var coordinate: CLLocationCoordinate2D
    @State private var region = MKCoordinateRegion()

    var body: some View {
        Map(coordinateRegion: $region)
            .onAppear {
                setRegion(coordinate)
            }
    }

    private func setRegion(_ coordinate: CLLocationCoordinate2D) {
        region = MKCoordinateRegion(
            center: coordinate,
            span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
        )
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView(coordinate: CLLocationCoordinate2D(latitude: 34.011_286, longitude: -116.166_868))
    }
}
}}
-LandmarkDetailにlandmarkプロパティを追加。修正。
#pre{{
struct LandmarkDetail: View {
    var landmark: Landmark

    var body: some View {
        ScrollView {
            MapView(coordinate: landmark.locationCoordinate)
                .ignoresSafeArea(edges: .top)
                .frame(height: 300)

            CircleImage(image: landmark.image)
                .offset(y: -130)
                .padding(.bottom, -130)

            VStack(alignment: .leading) {
                Text(landmark.name)
                    .font(.title)
                    .foregroundColor(.primary)

                HStack {
                    Text(landmark.park)
                    Spacer()
                    Text(landmark.state)
                }
                .font(.subheadline)
                .foregroundColor(.secondary)

                Divider()

                Text("About \(landmark.name)")
                    .font(.title2)
                Text(landmark.description)
            }
            .padding()
        }
        .navigationTitle(landmark.name)
        .navigationBarTitleDisplayMode(.inline)
    }
}


struct LandmarkDetail_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            LandmarkDetail(landmark: landmarks[0])
        }
    }
}

}}


*Generate Previews Dynamically [#ofc48995]
プレビューを修正する。
-LandmarkListを修正。まとめてプレビューできる。
#pre{{
struct LandmarkList: View {
    var body: some View {
        NavigationView {
            List(landmarks) { landmark in
                NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationTitle("Landmarks")
        }
    }
}

struct LandmarkList_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone SE (2nd generation)", "iPhone XS Max"], id: \.self) { deviceName in
            LandmarkList()
                .previewDevice(PreviewDevice(rawValue: deviceName))
                .previewDisplayName(deviceName)
        }
    }
}
}}

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS