見出し画像

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)

詳細画面のボタンが表示されるようになります。

この記事が気に入ったらサポートをしてみませんか?