SwiftUI 入門やるよ!チュートリアルしてみる!v2 リスト作成とナビゲーション

SwiftUI

v1はこちら

SwiftUI 入門やるよ!チュートリアルしてみる!v1 viewを組み合わせよう
型を作っておこうかなと思い。まずはチュートリアルをやってみます!時間25分らしいです!頑張りましょう!SwiftUI essentials Creating and combining views...

v2 Building lists and navigation リストとナビゲーション

Building lists and navigation | Apple Developer Documentation
With the basic landmark detail view set up, you need to provide a way for users to see the full list of landmarks, and to view the details about each location.

こちらを進めます!

section 1 Create a landmark model ランドマーク一覧のデータですね

チュートリアルのプロジェクトをダウンロードして

Resources の landmarkData.json を使います。

プロジェクトは、v1の続きを使います。

Landmarksの下にResources グループを作成、そこにjsonを追加

Resourcesディレクトリにjsonファイルを入れました。

Copy items if neededをチェックしてFinish

landmarkDataが入りました。

File > New > File. ..
Swift Fileを作ります

Landmark.swiftです。ランドマークアイテム用ですね

サンプルからランドマークのjpgをAssetsに入れます

一つ前のturtlerockも含めてimagesディレクトリをそのままAssetsに入れました

import Foundation
import SwiftUI
import CoreLocation

struct Landmark : Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var desctiption: String
    
    private var imageName: String
// SwiftUIが必要
    var image: Image {
        Image(imageName)
    }
    
    private var coordinates: Coordinates
// CoreLocationが必要
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }

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

import SwiftUI も見慣れそうですね^^
Imageを呼び出すプロパティ追記です

位置情報、Coordinatesを作って。

ところで Hashable, Codable ? の意味をここで見ておきましょう

Hashable
ハッシュ化できるということのようです、要素として取り回すときは必要?そうです

Codable
コード化できるということで、たとえばjsonにエンコード、デコードできるようになるようです!

なるほどですね

ModelData.swift を作成。モデル、json読み出しの関数も自分で書くようです?

import Foundation

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("Couldnt load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder =  JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldnt load \(filename) as \(T.self):\n\(error)")
    }
    
}

load関数、テンプレート(ジェネリック)やら例外処理やら初めてでも勉強になりますね

ファイルをグループ化する、View, Model, Resources と

section 2 create row view 列ビューを作成

swiftUI view で LandmarkRow.swift を作成

import SwiftUI

struct LandmarkRow: View {
    var landmark: Landmark
    
    var body: some View {
        HStack {
            Text(landmark.name)
        }
    }
}

#Preview {
    LandmarkRow(landmark: landmarks[0])
}


preview のところのコンストラクタで モデルで作成した var landmarks を使用して landmarks[0]を利用

HStack横並び。landmark.nameで名前表示

json読み込みエラー!!!Landmarkの変数名を間違えて jsonにない文字だったのでエラーに…

画像を読み込み、サイズしてして、Spacerで左寄せに

section 3 row previewをカスタマイズ

カスタマイズって日本語で?個別化、特注と書いてありました。

プレビューを切り替え

2つpreviewを置くと上で切り替え、名前もつけられると

Groupを使うと2つ並びました

section 4 リストを作ろう!

SwiftUI View で LandmarkList.swiftを作成

List に LandmarkRowを並べるだけで…wow

section 5 データを読み込んでリスト表示

list を landmarksから読むだけで、すべてリストに表示されました

struct Landmark : Hashable, Codable, Identifiable {
    var id: Int

Landmarkに Identifiableプロトコルを追加
id で一意になるそうです。同じidがあったらエラーになるのかな?特に重複チェックなどそういうものではないようです

最初は idを指定していましたが
List(landmarks, id: \.id) { 
Identifiableを使うと idは自動でid認識されるということのような
List(landmarks) {

section 6 一覧と詳細のナビゲーション

swiftui view作成 LandmarkDetail.swift

内容は前回作成したContentViewをそのままコピー

ContentViewは LandmarkListに変更
トップをこのリストの状態に

NavigationSplitViewを入れて
Listの中を NavigationLinkと labelを設定するとLandmarkDetail に遷移できました

リストからの詳細、詳細からリストが出来ました◎

section 7 Pass data into child views 各ビューにデータを渡します

名前と画像と位置情報

CircleImageには var image で呼び出すとき CircleImage(image: Image(…))

MapView には var coordinate: CLLocationCoordinate2D を追加して MapView(coordinate: … )
Mapの呼び出しは Map(position: .constant(.region(region))) と データ変更で切り替わる形に

LandmarkDetailには var landmark:Landmark で呼び出しは LandmarkDetail(landmark: …)で

各所 渡したデータを利用するように変更していきます。

LandmarkDetailは VStackを ScrollViewに変更しました。
すると詳細が長文で切れているところがスクロールで表示できるようになりました

section 8 機種ごとのプレビューを表示?

iPadに変更してみると

表示がタイトルだけになりました select a landmarkだけに

iPad 左上の青っぽいツールバーアイコンを押すと左にリストが表示されます

これが NavigationSplitView ということですね

ここで横向きに出来たりします

ダイブできる感ありますね^^

Check Your Understanding

Great job, you’ve answered all the questions for this tutorial.

無事終わりました。選択肢の英語難しい…英語の意味がわからんですね^^;;;;
超簡単な英語だとは思うのですが基本が難しい…

次はユーザー入力操作

SwiftUI 入門やるよ!チュートリアルしてみる!v3 ユーザー入力操作
前回はこちらユーザー入力!Handling user inputsection 1 お気に入りにマークするModel/LandmarkにisFavoriteを追加LandmarkRowに...

お気軽にコメントください!

スパム対応のためコメント認証に数日かかることがありますが、お気軽にコメントいただけると嬉しいです^^

コメント

タイトルとURLをコピーしました