プログラミング

【第7回】日本語版SwiftUIチュートリアル【UIコントロールの動作】

日本語版SwiftUIチュートリアル

日本語版SwiftUIチュートリアル

日本語版SwiftUIチュートリアル

本チュートリアルは,Appleが掲載している公式のSwiftUIチュートリアルを「日本語で」そして「詳細に」解説し直すことを目的とした記事です.

この手の記事は,他にも似たようなものがありますが,全てを網羅しているわけではなく,部分的に解説している記事が多数です.

そこで,SwiftUIを使ってアプリ開発をしたい方々のために,そして勉強している自分自身のために,日本語版SwiftUIチュートリアルの完全版を書きます.

なお,本記事の難易度としては,初級者も見様見真似で作れるようにはなっていますが,それでは物足りないという中級者のために,細かい文法的な解説も随所に入れていこうと思います.

注意として,本記事はSwiftの言語解説はあまり含まないので,以下の記事を別タブで開いておいて,分からなければ逐一確認してみると良いと思います.

  1. Swiftを触ったことがないプログラマーのためのSwiftチュートリアル

 

ちなみに出来上がるアプリは,上図に示すような観光地アプリです.

各観光地の位置情報を確認したり,その観光地をお気に入りに追加したりできるアプリを目指します.

第1回は????

日本語版SwiftUIチュートリアル

第7回:UIコントロールの動作

第7回では,第4回から作成していたものを用いて,ユーザのプロフィール情報を変更・管理するビューを作成していきます.

この回では,プロフィール画面からユーザのプロフィールをUIコントロールを用いて簡易的に変更できるようにします.

ついに全てのビューがここで繋がりますので,頑張っていきましょう.

Step 1. ユーザプロフィールを表示する

まずは,新たに「Profiles」というグループを作成しましょう.

階層は「Hikes」などと同じで構いません.

さらに,「Profile.swift」と言う名のプロフィール情報を管理する構造体を作成していきます.

この構造体では,ユーザ名,通知ON/OFF,季節の写真,ゴールした日,デフォルトのプロフィールを管理します.

したがって,

ひとまずこのような形にしましょう.

この部分,自身の構造体のインスタンスを内部でプロパティとして保持していますが,これはシングルトンというデザインパターンの一種です.

シングルトンは一言で表せば「インスタンス(オブジェクト)を一つしか持たない構造体やクラス」を指します.

プロフィール情報は各ユーザで,それぞれ複数のインスタンスを生成する必要がありませんので,このように制約をかけるのです.

また,Swiftではシングルトンは通常, static を用いて定義されます.

さて,この構造体を用いて実際にビューを作成していきます.

まず動作確認がてら,Profileを管理する「ProfileHost.swift」を作ってコーディングしていきましょう.

ひとまず以下の形を,ベースとしておきます.

日本語版SwiftUIチュートリアル

うまく動作していますね.

次に,プロフィール詳細を管理するためのビュー「ProfileSummary.swift」を先に作成します.

日本語版SwiftUIチュートリアル

こちらもこのような感じにしておきましょう.

特筆すべきことはありません.

これを,ProfileHostから呼び出します.

これも問題なく動作するはずです.

さて次に,Hikes/ディレクトリに新たに「HikeBadge.swift」を作成してください.

前に作成したBadgeを使って,プロフィールに獲得したバッジを並べてみましょう!

日本語版SwiftUIチュートリアル

次に,これをProfileSummaryで並べてみましょう.

日本語版SwiftUIチュートリアル

段々クールなビューに仕上がってきましたね.

さらに,Hikeの情報も盛り込んでいきましょう!

まずは hikeData を監視可能をオブジェクトとします.

あとは,ProfileSummaryで呼び出すだけです.

日本語版SwiftUIチュートリアル

ここまでくると,段々勝手がわかってきますね.

本ステップ最後に,CategoryHomeからこのプロフィールにアクセスできるようにしましょう.

日本語版SwiftUIチュートリアル

日本語版SwiftUIチュートリアル

プロフィールの表示はシート(Sheet)と呼ばれるビューを用いています.

下からビューがニョキっと覆い被さるビューです.

仕上げに,リストの余白を整えればひとまず完成です.

日本語版SwiftUIチュートリアル

Step 2. 編集モードを追加する

次に,ユーザのプロフィールを編集できるようにしていきましょう.

ここでは,簡易的に「ユーザ名」「季節の写真」を編集できる機能を実装していきます.

早速「ProfileHost.swift」を編集していきますが,今の段階ではプレビューが動作しません.

これは,子ビューである「ProfileSummary」で環境オブジェクトが使用されているからです.

なので,以下のようにProfileHostでも環境オブジェクトを渡してあげましょう.

これで,再びプレビューが利用できるようになるはずです.

さて本題に移りますが,SwiftUIではあらかじめ「編集モード (EditMode)」という機能が実装されています.

これはその名の通り,もともとのビューと編集ビューを切り替えるために用意されています.

まずは見様見真似で実装してみましょう.

最初に,編集モードか否かを保持するプロパティ editMode を定義しました.

\.editMode はKeyPathで,名前がプロパティ名と同じでややこしいですが,これとは別です.

そうしたら,編集ボタンもあらかじめ用意されているのでビューに追加しましょう.

日本語版SwiftUIチュートリアル

右上に編集ボタンが現れました.

まだ押してもビューは何も変わりません.

今から編集ビューを実装していくのですが,ユーザプロフィールが環境オブジェクトにないため編集したとしても,その内容が他のビューに共有されません.

そこで,あらかじめUserDataにプロフィールデータを追加しておきましょう.

そうしたら,ProfileHostを以下のように修正します.

ここまでは,プレビューになんら変化はないです.

ここで編集ビューはまだ作成していませんが,編集モード切り替えがうまく動作するかだけ確認してみましょう.

これで「Edit」ボタンを押すことでビューの切り替えができるはずです(まだテキストだけの質素なビューですが...).

また,一旦 draftProfile は置いておきます (別にコメントアウトはしなくても良いです).

...

さて, editMode?.wrappedValue は,Optional型である editMode をアンラップしているわけですが, ? (はてな/クエスチョンマーク)によるアンラップは初めましての方も多いでしょう.

通常,強制的なアンラップでは ! を用いることがありますが,これを利用した場合, nil が出たときにランタイムエラーが出力されアプリがクラッシュします.

そこで, ? を使ったアンラップをするわけですが,これをOptional Chainingと呼んでいます.

Optional Chainingの場合はランタイムエラーは発生しません.

公式のドキュメント「Optional Chaining」では,Optional Chainingで nil が出た時は「fails gracefully (潔く失敗する)」と書かれていますね.

まあこれはともかく, editMode は列挙型なので .wrappedValue で,その値を取り出していることを意味しています.

それが, .inactive (アクティブでない) ならばProfileSummaryを表示する,そのようなコードになっています.

Step 3. 編集ビューを定義する

そうしたら最後に,編集ビューを作成していきましょう!

編集ビューは,ユーザデータを編集するためのものですが,もちろん編集されてはいけないものもあります(例えばバッジとか).

そういったもの以外を編集できるようなビューを構築していきます.

まずは新たに「ProfileEditor.swift」を作成しましょう.

初期は以下のようなコードにしておきます.

日本語版SwiftUIチュートリアル

ここで, @Binding が初登場ですが,これは @State と同じく「ビューを超えて変更を通知する」ためのPropatyWrapperです.

基本的には2つとも同じような挙動をとるのですが,違いはなんでしょう?

違いは親ビューで定義された @State プロパティは外部ビューからのアクセスを基本的に受け付けないという点です( private 修飾子を付けるのを推奨しているため).

しかし,子ビューにおいても同じくそのプロパティの値を直接変更したい場合がよくあります.

そのようなときに, @Binding プロパティとして定義してあげるのです.

要するに,親ビューで定義された @State プロパティを子ビューで扱うためには, @Binding プロパティとして定義する,ということです.

また,前にも登場しましたが, @State および @Binding プロパティの値を編集するときには, $ を付けてあげましょう.

そうしたら,ProfileHostに戻り今作成した編集ビューを紐付けます.

ここで, draftProfile を渡す形にしておきます.

今の段階では,編集ビューで編集したユーザ名の反映はまだされませんが,ビューの切り替えがうまくいっていることを確認してください.

また,ProfileEditorに戻ります.

次に,観光地に関するイベント通知を行うか否か,を切り替えるトグルスイッチを追加してみましょう.

日本語版SwiftUIチュートリアル

続いて,季節の写真を選ぶための,Pickerコントロールを配置します.

ここで列挙型の全ケースを取得する方法も覚えておきましょう.

日本語版SwiftUIチュートリアル

ちなみに, .pickerStyle(SegmentedPickerStyle()) を記述しないと,デフォルトの縦型ロールのPickerスタイルになります.

最後に,DatePicker (日付選択コントロール) を追加して,観光地訪問の目標日付を選択できるようにしましょう.

Swiftの Calendar の使い方も直感的でわかりやすいですね.

ちなみに, a..<b はRangeオブジェクト, a...b はClosedRangeオブジェクトになります.

Countableか否かもRangeオブジェクトには存在しますが,そのあたりはこれらの単語で調べてみると良いでしょう.

今回は割愛します.

うまく実装できていれば,下図のようにカレンダーで日付設定ができるようになっているはずです.

日本語版SwiftUIチュートリアル

Step 4. 編集の伝達を遅らせる

第7回最後のステップです.

ユーザの編集中には,その内容変更を他のビューに伝達しないようにする必要があります.

もし,途中で編集内容を破棄 (Cancel) したくなったら?

そのようなときは,編集内容を確定するまで,下書き保存に割り当てておき,編集が確定したら本物のコピーを取るようにすれば良いのです.

まず最初に,ProfileHostのEditボタンの横に,新たに「Cancel」ボタンを追加しましょう.

そのときに, draftProfile (下書きプロフィール) を利用して,編集前のデータを保持しておきます.

最後に,編集した内容を更新するようにすれば編集機能が全てうまく動作するはずです.

このとき, onAppear(perform:) 修飾子と onDisappear(perform:) 修飾子を利用します.

編集モードで「Done」ボタンを押したときには前者,「Cancel」ボタンのときは後者が反応します.

日本語版SwiftUIチュートリアル

うまく編集が同期できましたか?

Done/Cancelどちらもうまく動作するか確認してみてください.

第7回:おわりに

お疲れ様でした.

いよいよ本チュートリアルも終盤に入ります.

あとは,UIをもう少し整えて完成させるだけですが,Apple watchOSやmacOSにも対応させるにはどうすれば良いのかなどもチュートリアルに含まれています.

残すところ,あと3回頑張っていきましょう!

 


スポンサードリンク