SwiftUI Tutorials②: Building lists and navigationでSwiftUIを初めてみよう！

# SwiftUI Tutorials
Apple公式が出しているSWiftUIのチュートリアルです！
今回は「リストとナビゲーションを構築する」というチュートリアルのリストの作成とナビゲーションの設定でつまずいたところを共有します！

https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

# Listの作成 (静的リスト作成・動的リスト作成)
SwiftUIのList型を使うとき、プラットフォーム固有のビューのリストを表示できる。リストの要素は、これまでに作成したスタックの子ビューのように静的であることも、動的に生成されることもできる。
## 静的リスト作成
静的 = 「変化しないもの」
List一覧が生成されます！リストの要素を個別に指定する！

```swif: LandmarkList.swift
 import SwiftUI
 
 struct LandmarkList: View {
     var body: some View {
         List {
             LandmarkRow(landmark: landmarks[0])
             LandmarkRow(landmark: landmarks[1])
         }
     }
 }
 
 #Preview {
     LandmarkList()
 }
```
下記のように、リストに入っているのは2つという限られた個数であるため、リストの要素を個別に指定し、値をJSON形式のファイルから取得することができます！
![4a32a57be1cdeb25f9468ffbc37b1df3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/46c479d8-06e5-6f62-8754-bd198b849a70.png)

## 動的リスト作成
動的 = 「変化するもの」
リストは識別可能なデータで動作する！
データを識別可能にするには、次の2つの方法がある！
### ① 各要素を一意に識別するプロパティへのキーパスをデータと一緒に渡す方法
### ② データ型をIdentifiableプロトコルに準拠させる方法


### ① 各要素を一意に識別するプロパティへのキーパスをデータと一緒に渡す方法
キーパスであるid: \.idとデータであるlandmarksを一緒に渡している！
```swif: LandmarkList.swift
import SwiftUI

struct LandmarkList: View {
    var body: some View {
        List(landmarks, id: \.id) { landmark in
            LandmarkRow(landmark: landmark)
        }
    }
}

#Preview {
    LandmarkList()
}
```
### ② データ型をIdentifiableプロトコルに準拠させる方法
Identifiable「識別可能」
Identifiableプロトコルに準拠した構造体は、idを割り振ることができるということ。
idが振られることでSwiftUI側はどのコンテンツのデータを更新すればいいのかがわかる。

https://developer.apple.com/documentation/swift/identifiable



```Landmark.swift
struct Landmark: Hashable, Codable, Identifiable {
    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
    }
}

```
※もし、Identifiableプロトコルに準拠させないと、下記のようなエラーになるので注意！
エラー：Initializer 'init(_:rowContent:)' requires that 'Landmark' conform to 'Identifiable'
配列の要素を一意に識別できるキー値がないため、配列の値を取り出すことができない

```swif: LandmarkList.swift
import SwiftUI

struct LandmarkList: View {
    var body: some View {
        List(landmarks) { landmark in
            LandmarkRow(landmark: landmark)
        }
    }
}

#Preview {
    LandmarkList()
}
```
①と②どちらの方法でも以下のようなViewが作成される！
![ef100129cbb3b2cbe09cfc09df60af5c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/59fb3708-1468-099d-e9fa-51938c72f1fd.png)

# Navigation
### NavigationSplitView
NavigationSplitViewは、ビューを2列または3列で表示するビューで、先頭の列での選択が後続の列での表示を制御する。

https://developer.apple.com/documentation/swiftui/navigationsplitview

ナビゲーションスプリットビューは、選択した後に表示されるビューのプレースホルダとなる2番目の入力を受け取る。iPhoneの場合、スプリットビューにプレースホルダは必要ありませんが、iPadの場合、誰かが選択する前に詳細ペインを表示することができる。

NavigationSplitViewを使って画面構築をした時、
iPhoneやApple Watchなどの狭いサイズのデバイスの場合、ナビゲーションの分割ビューが1つのスタックに折りたたまれたコンパクトカラムとして構成される!

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/ebd47573-8c54-31ba-ece2-a6197a596968.png" width=300>

iPadの場合、詳細を選択する前にすでに2分割になっているリストビューが表示されている。detailの後に記述が必要になる！
2列（カラム）のレイアウトが表示される！


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/e867b6e7-0bc2-d5e6-9709-0485fc5a76f0.png" width=300>

### NavigationLink
NavigationLinkとは、ナビゲーション・プレゼンテーションを制御するビュー

https://developer.apple.com/documentation/swiftui/navigationlink

ナビゲーションリンクをタップすると、NavigationStackまたはNavigationSplitView内のビューが表示される！リンクのラベルクロージャにビューコンテンツを提供することで、リンクの視覚的な外観を制御できます。例えば、Labelを使ってリンクを表示することができる！

```swif: LandmarkList.swift
import SwiftUI

struct LandmarkList: View {
    var body: some View {
        NavigationSplitView {

            List(landmarks) { landmark in
                NavigationLink {
                    //②詳細説明へ遷移
                    LandmarkDetail(landmark: landmark)
                } label: {
                    //①リスト行のリンクを押すと、
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationTitle("Landmarks")
        } detail: {
            //iPadの場合表示
            Text("Select a Landmark")
        }
    }
}

#Preview {
    LandmarkList()
}
```
①リスト行のリンクを押すと、②詳細説明へ遷移することができました！

![15e0f25dab32545ef3e14d3a496736ec.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/2c4664b3-885b-077e-147a-84d74c330ef2.gif)


# 参考文献

https://tech.amefure.com/swift-identifiable

https://shuhey-hashimoto.com/swiftui/%E3%80%90%E3%81%96%E3%81%A3%E3%81%8F%E3%82%8A%E8%A7%A3%E8%AA%AC%E3%80%91identifiable%E3%81%A8%E3%81%AF%EF%BC%9F-swift%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B/

https://blog.code-candy.com/swiftui_navigationsplitview/

https://zenn.dev/oka_yuuji/articles/507495600871a4

https://blog.studysapuri.jp/entry/2021/09/18/iosdc-swiftui-navigationlink-push-navigation