前回はこちら

ユーザー入力!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 線と図形描画?



コメント