はじめに
前回からの続きでSwiftUIのチュートリアル入門で、[Handling User Input編]になります。
もと記事サイト

Step0
このセクションではLandmarkの詳細画面にお気に入りボタンを設置し、お気に入りの登録・解除の変更を@Bindingを使用してModelDataに反映するようにします。
Step1
最初にお気に入りボタンとなるFavoriteButton.swift.を作成します。
import SwiftUI
struct FavoriteButton: View {
var body: some View {
Text("Hello, World!")
}
}
struct FavoriteButton_Previews: PreviewProvider {
static var previews: some View {
FavoriteButton()
}
}Step2
isSetプロパティを宣言します。その際に@Bindingを付与します。これでisSetの変更内容がModelDataのisFavoriteに反映されるようにします。
またFavoriteButton_PreviewsにもイニシャライザでisSetを渡します。@Bindingを付与しているためisSetの型が@Binding<Bool>となっているので、.constant(true)で変換します。
import SwiftUI
struct FavoriteButton: View {
@Binding var isSet: Bool
var body: some View {
Text("Hello, World!")
}
}
struct FavoriteButton_Previews: PreviewProvider {
static var previews: some View {
FavoriteButton(isSet: .constant(true))
}
}Step3
ボタンを設置します。ボタンを押された際にisSetの値を反転します。
お気に入りボタンらしくなるように星の画像も追加します。
import SwiftUI
struct FavoriteButton: View {
@Binding var isSet: Bool
var body: some View {
Button(action: {
isSet.toggle()
}) {
Image(systemName: isSet ? "star.fill" : "star")
.foregroundColor(isSet ? Color.yellow : Color.gray)
}
}
}
struct FavoriteButton_Previews: PreviewProvider {
static var previews: some View {
FavoriteButton(isSet: .constant(true))
}
}Step4
ファイルが増えてきたのでフォルダーを作成して整理します。CircleImage.swift、 MapView.swift、FavoriteButton.swiftをHelpersフォルダーを作成して中にいれます。Landmarksフォルダーを作成しLandmarkList.swift、LandmarkRow.swift、LandmarkDetail.swiftを中にいれます。

Step5
LandmarkDetail.swiftを選択し、対象のLandmarkがModelDataのlandmarks配列の何番目に保存されているのか比較できるように、@EnvironmentObjectでmodelDataを親Viewから受け取れるようにします。LandmarkDetail_Previewsにも変更を加えます。
比較する際にlandmarkIndexを使用してidが一致する要素番号を取得しています。
import SwiftUI
struct LandmarkDetail: View {
@EnvironmentObject var modelData: ModelData
var landmark: Landmark
var landmarkIndex: Int {
modelData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}
var body: some View {
ScrollView {
MapView(coordinate: landmark.locationCoordinate)
.ignoresSafeArea(edges: .top)
.frame(height: 300)
CircleImage(image: landmark.image)
.offset(y: -60)
.padding(.bottom, -60)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
HStack {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
.font(.subheadline)
.foregroundColor(.secondary)
Divider()
Text("About \(landmark.name)")
.font(.title2)
Text(landmark.description)
}
.padding()
}
.navigationTitle(landmark.name)
.navigationBarTitleDisplayMode(.inline)
}
}
struct LandmarkDetail_Previews: PreviewProvider {
static let modelData = ModelData()
static var previews: some View {
LandmarkDetail(landmark: modelData.landmarks[0])
.environmentObject(modelData)
}
}
Step6
landmarkの名前を表示しているTextをHStackで囲み、FavoriteButtonを追加します。
その際のイニシャライザにisSetにmodelData.landmarks[landmarkIndex].isFavoriteを渡しますが、先頭に$を付与することでisSetとmodelData.landmarks[landmarkIndex].isFavoriteをバインドさせてmodeldataのlandmark.isFavoriteを自動で更新させています。
import SwiftUI
struct LandmarkDetail: View {
@EnvironmentObject var modelData: ModelData
var landmark: Landmark
var landmarkIndex: Int {
modelData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}
var body: some View {
ScrollView {
MapView(coordinate: landmark.locationCoordinate)
.ignoresSafeArea(edges: .top)
.frame(height: 300)
CircleImage(image: landmark.image)
.offset(y: -60)
.padding(.bottom, -60)
VStack(alignment: .leading) {
HStack {
Text(landmark.name)
.font(.title)
FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
}
HStack {
Text(landmark.park)
.font(.subheadline)
Spacer()
Text(landmark.state)
.font(.subheadline)
}
.font(.subheadline)
.foregroundColor(.secondary)
Divider()
Text("About \(landmark.name)")
.font(.title2)
Text(landmark.description)
}
.padding()
}
.navigationTitle(landmark.name)
.navigationBarTitleDisplayMode(.inline)
}
}
struct LandmarkDetail_Previews: PreviewProvider {
static let modelData = ModelData()
static var previews: some View {
LandmarkDetail(landmark: modelData.landmarks[0])
.environmentObject(modelData)
}
}
Step7
LandmarkList.swiftを選択し、ライブプレビューを実行してみましょう。
詳細画面で変更したお気に入りボタンのステータスが一覧画面に戻ると反映されていることが確認できます。

Landmarkの名前の隣にあるお気に入りの星をタップします。

一覧画面に戻ると先程の変更が反映されています!

まとめ
今回でHandling User Input編もお終いになります。ユーザのアクションを@Bindingを使用してデータソースと同期する方法がわかりました。これで簡単なアプリなら作成できそうですね。
次回からは[Drawing Paths and Shapes]編になります。図形の描画はレイアウト組む際に必要になることもあるので頑張って勉強しましょう。



コメント