Tag: SwiftUI/BuildingListsAndNavigation

目次

関連ページ

参考情報

Create a Landmark Model

  • データを保持するためのモデルを作成する。
  • landmarkData.jsonをプロジェクトのResourcesフォルダ以下にコピー。
  • New > FileでLandmark.swiftを追加。
  • 以下のように定義する。
    struct Landmark: Hashable, Codable {
        var id: Int
        var name: String
        var park: String
        var state: String
        var description: String
    }
    
  • 画像の関連付け
    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を追加。最終的に以下のように。
    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関数を作成する。
    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

  • LandmarkRow.swiftを追加。以下のように作成。
    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

  • プレビューの変更
    struct LandmarkRow_Previews: PreviewProvider {
        static var previews: some View {
            LandmarkRow(landmark: landmarks[1]).previewLayout(.fixed(width: 300, height: 70))
        }
    }
    
    
  • 二つ表示
           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

リストビューを実装する。

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

Make the List Dynamic

Listにコレクションを表示。

  • LandmarkListを変更。
    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

リストと詳細をナビゲートできるようにする。

  • SwiftUI ViewのLandmarkDetailを追加。
  • ContentViewの内容を移植。
    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を生成。
    struct ContentView: View {
        var body: some View {
            LandmarkList()
        }
    }
    
    
  • LandmarkListの中にNavigationViewを入れる。プレビューの上部に空白ができる。タイトルも追加。
    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

詳細ビューにデータを引き渡す。

  • CircleImageでimageを格納する。
    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プロパティを追加。
    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プロパティを追加。修正。
    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

プレビューを修正する。

  • LandmarkListを修正。まとめてプレビューできる。
    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
Last-modified: 2021-07-29 (木) 17:42:13