リバース・エンジニアリング

Flultterとテックブログと時々iOS

4. SwiftUI ListとNavigationViewでプッシュ遷移を実装する

SwiftUI での List と NavigationLink について調べてみました。
List は UIKit では UITableView に該当するコンポーネントです。
NavigationLink は NavigationView と一緒に使うコンポーネントで UIKit でいうことの push 遷移を実装できます。

今回は List を使ってリスト一覧を表示させてセルをタップしたら画面遷移して詳細画面にいくものを作ってみました。

先に作って見たもののスクリーンショットを貼っておきます。

トップ画面(ContentView) 詳細画面(DetailView)
f:id:qed805:20200725190526p:plain f:id:qed805:20200725190547p:plain

ソースコードはこちらです。
一覧を表示するデータのファイルを先に作っておきます。都道府県を配列に持たせました。

PrefectureData.swift

import Foundation

struct Prefecture: Identifiable {
    var id: Int
    let name: String
}

let prefectures: [Prefecture] = [
    Prefecture(id: 0, name: "北海道"),
    Prefecture(id: 1, name: "岩手県"),
    Prefecture(id: 2, name: "宮城県"),
    Prefecture(id: 3, name: "秋田県"),
    Prefecture(id: 4, name: "山形県"),
    Prefecture(id: 5, name: "福島県"),
    Prefecture(id: 6, name: "茨城県"),
    Prefecture(id: 7, name: "栃木県"),
    Prefecture(id: 8, name: "群馬県"),
    Prefecture(id: 9, name: "埼玉県"),
    Prefecture(id: 4, name: "千葉県"),
    Prefecture(id: 5, name: "東京都"),
    Prefecture(id: 6, name: "神奈川県"),
    Prefecture(id: 7, name: "新潟県"),
    Prefecture(id: 8, name: "富山県"),
    Prefecture(id: 9, name: "石川県"),
    Prefecture(id: 10, name: "福井県"),
    Prefecture(id: 11, name: "山梨県"),
    Prefecture(id: 12, name: "長野県"),
    Prefecture(id: 13, name: "岐阜県"),
    Prefecture(id: 14, name: "静岡県"),
    Prefecture(id: 15, name: "愛知県"),
]

これがテストデータになります。次に ContentView.swift に View を作ります。

ContentView.swift

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationView{
            List(prefectures) { prefecture in
                NavigationLink(destination: DetailView(prefecture: prefecture)) {
                    Text(prefecture.name)
                }
            }
            .navigationTitle("都道府県")
        }
    }
}

struct DetailView: View {
    
    var prefecture: Prefecture
    
    var body: some View {
        Text(prefecture.name)
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

画面遷移先の Viewとして DetailView を定義しました。
ContentView を見てみます。

NavigationView{
            List(prefectures) { prefecture in
                NavigationLink(destination: DetailView(prefecture: prefecture)) {
                    Text(prefecture.name)
                }
            }
            .navigationTitle("都道府県")
        }

このように

NavigationView > List > NavigatonLink (画面遷移先クラス) > Text

という階層になっているのが分かります。
NavigationView が UIKit の UINavigationView に該当する構造体かなと思ってます。
NavigationLink に destination のプロパティが存在します。destination は遷移先のクラスを代入すればOKです。
遷移先のクラスが DetailView で

var prefecture: Prefecture

のプロパティを定義しているので都道府県のインスタンスを渡してやりました。

次に UINavigationView の定義先をちらっと見てみます。

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 7.0, *)
public struct NavigationView<Content> : View where Content : View {

    public init(@ViewBuilder content: () -> Content)

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    public typealias Body = Never
}

このようにstruct で定義されていますね。
SwiftUI のコンポーネントが struct で出来ているのが分かります。

こんな感じで UIKit では UITableView (将来depricatedになるクラス)からセルをタップして画面遷移させてましたが、 SwiftUI では List を多様する将来が見えますね。

さらにiOS 14から Grid という UIKit でいうところの UICollectionView のコンポーネントも登場したので より一層複雑なUIをシンプルに組めるようになりました。

こんな感じで今日は終わろうと思います。

それでは、バイバイ。