前回はこちら
ユーザー入力!Handling user input
section 1 お気に入りにマークする
Model/LandmarkにisFavoriteを追加
LandmarkRowに isFavoriteのとき Image star.fillを表示
if landmark.isFavorite { Image(systemName: "star.fill") .foregroundStyle(.yellow) // .foregroundColor(.yellow) }
systemNameは SF Symbols
SF Symbolsはこちらに
https://developer.apple.com/jp/sf-symbols/
8000もあるそうです…なんでもありそうですね^^
アニメーションやら色々使えるっそうです
section 2 リストフィルター
isFavoriteみたいなのを表示するだけという
LandmarkList に @Stateを追加
@State private var showFavoritesOnly = false
struct LandmarkList: View { @State private var showFavoritesOnly = true // フィルターされたlandmarksを生成 var filteredLandmarks: [Landmark] { landmarks.filter { landmark in (!showFavoritesOnly || landmark.isFavorite) } } var body: some View { NavigationSplitView{ // フィルターされたものを読み込み List(filteredLandmarks) { landmark in NavigationLink{ LandmarkDetail(landmark: landmark) } label: { LandmarkRow(landmark: landmark) } } .navigationTitle("Landmarks") } detail: { Text("select a landmark") } } }
showFavoritesOnlyを trueにするとスター付きのみに
section 3 add control to toggle the state ステートをトグルでコントロールする
LandmarkList の List に ForEachを入れる。動的と静的の混在ができるそうな? 毎回foreach入れててもよいのかな?
今回は、 Listの中に Toggle と ForEach の2つが入る形
@State にアクセスするときは $ をつける
List に .animation(.default, value: filteredLandmarks) をつけると少しニュルッと動く
そのままですがシンプルに動きました。
section 4 use observation for storage ストレージ監視?観察
jsonファイルのデータ書き換えを監視?
@Observable class ModelData { }
@Observableをつけて class ModelData作成
observableのプロパティが変わるとswiftui viewが更新される?
ソースコード選択範囲の移動
行を選択状態のとき command + option + { で上 }で下に移動できる
var landmarksをModelDataの中に移動
@Observable class ModelData { var landmarks: [Landmark] = load("landmarkData.json") }
section 5 Adopt the model object in your views . モデルオブジェクトを採用
LandmarkList に @Environment(ModelData.self) var modelData を追加
Environmentは環境変数的にデータを渡せるようにするものらしい
#Preview { LandmarkList().environment(ModelData()) }
previewから LandmarkListを呼ぶときに environmentでModelData()を渡しているので @EnvironmentでModelData.selfを使えると
LandmarkRowとLandmarkDetail の previewの読み出しも変更しておく
#Preview { let landmarks = ModelData().landmarks return LandmarkDetail(landmark: landmarks[0]) }
ContentViewの呼び出しも
#Preview { ContentView().environment(ModelData()) }
environmentで渡すのはあまり良くないっぽいけどとりあえず?
LandmarkApp にもModelDataからの読み出しを追加
@main struct LandmarksApp: App { @State private var modelData = ModelData() var body: some Scene { WindowGroup { ContentView().environment(modelData) } } }
これで全部動きましたと。
section 6 favorite ボタンを追加
swiftui view で FavoriteButton.swift
@Binding を使って元データと連携
struct FavoriteButton: View { @Binding var isSet: Bool var body: some View { Button { isSet.toggle() } label: { Label("Toggle Favorite", systemImage: isSet ? "star.fill":"star") .labelStyle(.iconOnly) .foregroundStyle(isSet ? .yellow:.gray) } } } #Preview { FavoriteButton(isSet: .constant(true)) }
Buttonを追加してタップでisSet.toggle / 表示は★ isSetにより変更
Binding : landmarkのisFavoriteとisSetを繋ぐ作業
LandmarkDetailにて
struct LandmarkDetail: View { // environment呼び出しに @Environment(ModelData.self) var modelData var landmark: Landmark var landmarkIndex: Int{ // 現在のlandmarkのインデックスを取得、配列利用のため modelData.landmarks.firstIndex(where:{$0.id == landmark.id})! } var body: some View { // 渡されたmodelData を Bindableで使用 @Bindable var modelData = modelData ScrollView { MapView(coordinate: landmark.locationCoordinate) .frame(height:300) CircleImage(image: landmark.image).offset(y:-130).padding(.bottom,-130) VStack(alignment:.leading) { HStack{ Text(landmark.name) .font(.title) // 現在のindexを使用してlandmarkデータを渡す。Bindingされているので、on offが反映される。 FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite) } HStack { Text(landmark.park) .font(.subheadline) Spacer() Text(landmark.state).font(.subheadline) } Divider() Text("About \(landmark.name) ").font(.title2 ) Text(landmark.description).font(.subheadline) }.padding() } .navigationTitle(landmark.name) .navigationBarTitleDisplayMode(.inline) // Spacer() } } #Preview { let modelData = ModelData() return LandmarkDetail(landmark: modelData.landmarks[0]).environment(modelData) }
List -> Detail -> Button とBindingされるので、LandmarkList の preview操作で
DetailでのButtonでisFavorite変更が、Listに戻ったときも反映されている
#Preview { LandmarkList().environment(ModelData()) }
ListのpreviewのModelDataが変更される。まだjson保存は何もしていない
Check Your Understanding
Great job, you’ve answered all the questions for this tutorial.
相変わらず英語難しい。正解っぽいのはわかるけど翻訳しないと正解はわからない^^;
次は!?
Drawing paths and shapes 線と図形描画?
コメント