SwiftUI Tutorials - Handling User Input 2
Use an Observable Object for Storage
Favoriteを自由に追加してフィルターで選択できるようにしていきます。操作に対して画面を変更します。いわゆる非同期によるデータ監視を行うために"Combine"で実装していきます。
ModelData.swift
の変数"landmarks"を、
import Combine
final class ModelData: ObservableObject {
}
と定義し、
var landmarks: [Landmark] = load("landmarkData.json")
を入れると以下になります。
final class ModelData: ObservableObject {
@Published var landmarks: [Landmark] = load("landmarkData.json")
}
入れ込む時に
import Combine
と
ObservableObject
に適応するために、"@Published"をつける必要があります。
@Published var landmarks
とします。
Adopt the Model Object in Your Views
作った"ModelData()"を適応していきます。
実際に表示させるLandmarkDetail.swiftの構造体"LandmarkList"を変更して,
modelDataが使えるように
@EnvironmentObject var modelData: ModelData
@State private var showFavoritesOnly = false
@EnvironmentObject var modelData: ModelData
EnvironmentObjectを宣言して使うことによしデータを自動的に取得できるようになります。
変更前
var filteredLandmarks: [Landmark] {
landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
変更後
var filteredLandmarks: [Landmark] {
modelData.landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
modelData.landmarks.filter {}
を追加しています。
そして全体のアプリにこの
@EnvironmentObject var modelData: ModelData
を反映させるためにLandmarksApp.swiftのコードに
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(modelData)
}
}
.environmentObject(modelData)
を付け加えます。これでXcodeのsimulatorと実機で動作するようになります。
次にボタンを設置してユーザーが自由に"Favorite"をオンオフできるようにします。
FavoriteButton.swiftという名前のSwiftUI新規ファイルを作ります。
@Binding var isSet: Bool
を設置します。これでViewの画面での変更がデータソース(FavoriteButton)に伝播され処理されるようになります。
そしてボタンの実装です。構造体"FavoriteButton"を作って、var body: some View {}の中に以下実装します。
Button(action: {
isSet.toggle()
}) {
Image(systemName: isSet ? "star.fill" : "star")
.foregroundColor(isSet ? Color.yellow : Color.gray)
}
そしてボタンを設置するView(表示画面)についてコードを追加していきます。(LandmarkDetail.swiftの構造体"LandmarkDetail")
@EnvironmentObject var modelData: ModelData
var landmarkIndex: Int {
modelData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}
を追加します。
そしてCircleImage()の下にボタンを追加します。
CircleImage(image: landmark.image)
.offset(y: -130)
.padding(.bottom, -130)
VStack(alignment: .leading) {
HStack {
Text(landmark.name)
.font(.title)
.foregroundColor(.primary)
FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
ボタン部分です。
FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
詳細画面のボタンが表示されるようになります。
この記事が気に入ったらサポートをしてみませんか?