ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
SwiftUIの基本
SwiftUIでAppを構築する最初の1歩を踏み出しましょう。ビューとその仕組みについてご確認ください。基本的なコントロールから、リストやナビゲーションスタックなどの洗練されたコンテナまで、SwiftUIでは優れたユーザーインターフェイスをより早く簡単に作成できます。ボタンのような基本のコントロールは、シンプルでありながらさまざまな用途に用いることができます。このセッションでは、SwiftUIでそうした要素を機能満載のユーザーインターフェイスへと構成して、優れたAppの構築を円滑に進める方法について説明します。Appleの新しい宣言型フレームワークの基本を学びながら、SwiftUIのスキルを身に付けましょう。
リソース
関連ビデオ
WWDC21
WWDC20
WWDC19
-
ダウンロード
(音楽)
(拍手) おはよう (拍手) SwiftUI Essentialsへようこそ 私はSwiftUIチームの マット・リケットソンです あとで同僚のテイラーも登場します SwiftUIが気に入った人は? (拍手) 私もSwiftUIの話がしたくて ウズウズしています 内容が盛りだくさんなので 早速始めましょう
SwiftUIは優れたアプリケーションを 最も短いパスで作るための 新しいフレームワークです すばらしいユーザインターフェイス を作る最短の道だということです
新しいとはいえSwiftUIには 皆さんになじみ深い部分も多くあります
UIフレームワークの基本的な コンポーネントを使っているからです ボタンやテキストフィールドといった ものもあれば スタックやリストといった レイアウトコンテナ ドローイングやアニメーション ジェスチャもあります また プラットフォーム固有の 概念もあります MacのメニューやApple Watchの Digital Crown Apple TVの Siri Remoteなどと同じです SwiftUIは今までの機構と まったく違うものではありません
しかしコンポーネントの使い方を 知っているだけでは 魅力的なアプリケーションは 作れませんよね
良いアプリケーションには 次のような要素が必要です アクセシブルであり Dynamic Typeと連動し 異なるデバイスや画面サイズ インプットにも適応すること また双方向性のある アニメーションなども大切ですし ダークモードなどの システム機能のサポートも重要です
これらを使いこなして初めて 多くのユーザに役立つ 最新感覚の アプリケーションとなるのです
しかしご存じのように これがすべてではありません アプリケーション自体に 独自の特色がなければなりません
改めて学ばなければいけないことが たくさんあることが分かります いかに一貫性を維持したコードを 書くかなどです それに対し SwiftUIにできることは何でしょう?
ご自分のアプリケーションのことを 考えてみてください まず必要となる基本的な機能は コントロールやナビゲーション アクセシビリティや異なるデバイスへの レイアウトの適応などです 上質なアプリケーションを作るには 正しく設計しなければなりません
次にアプリケーションに特徴を持たせる カスタム機能も必要です この楽しい機能に 我々は情熱を注ぎました これらを設計したことに 誇りを持っています SwiftUIの目的はとてもシンプルです 特徴を持たせることに できる限りの時間を使い クオリティには妥協せず 基本的なことは最小限の時間でやる
それを実現するために 最短のパスを構築しました すでに皆さんはすばらしい アプリケーションを作っています それを少しだけ速く行う お手伝いをさせてください
このセッションではSwiftUIを より深く理解してもらいます コードの説明もしますが 優れたアプリケーションを作るために SwiftUIができることについても お話しします セッションが終わる頃には― SwiftUIでユーザインターフェイスを 設計できるようになっているでしょう
基本的なビューや モディファイアから始めます 例を使って説明します 私は自分が興味のあることを 例として取り上げることにしています 最近インターネットを使った人は “ミレニアム世代”に関する記事を 目にしたと思います 私は今それを 最も重要な問題と考えています そうです アボカドトースト問題です
(笑い)(拍手) ミレニアム世代の人は?
今日はアボカドトーストを注文する アプリケーションを作ります すでに少し作り始め ここまでできています
スマホを使って欲しいものを すぐに注文できる簡単なフォームです まだ手始めの段階ですが ここで完成させようと思います コードの話をする前に ビューについて少し触れます
ビューはユーザインターフェイスの 基本的な部分だからです SwiftUIを使って作るもの すべてに重要です
UIKitやAppKitのような UIフレームワークを知っている人なら ビューという言葉はご存じだと思います
SwiftUIにもビューがあり 他のフレームワークと同じ働きをします
高次において ビューはUIの中の一部分と定義できます
アプリケーションで表されるすべては ビューによって定義されます
個々のコントロールもビューです それらを持つコンテナもビューです 画面上のすべてのピクセルも ある意味ビューと言えます
ユーザインターフェイスはビューを ヒエラルキー状に構成したものです
ルートのコンテナから始まり―
TextやImageやShapeが続きます
UIKitやAppKitを使ったことのある人なら この図は知っていますね ここで重要なのはSwiftUIのビューも 同じだということです
SwiftUIがこれまでのものと違う点は ビューのコードの書き方です コードを見てみましょう
この例ではVStackのコントロールと Textが使われています コードを読めば簡単に分かりますね
左にあるコードと右のヒエラルキー図が 非常に似ていることにお気づきでしょう
ルートにはStackがあります その中には Textとコントロールがあります
個々のTextのラベルは コントロールに含まれています
ここにないのはaddSubviewのような ファンクションを呼び出すものです ビューヒエラルキーを1つずつ 組み立てていく代わりに 完成済みの構造体を 初期化しているからです
なぜならSwiftUIは ビューを宣言型で定義するからです 命令型ではありません このコンセプトを説明する最もいい例が まさにアボカドトーストです ではこれを命令型で作ってみましょう
命令型は明瞭なコマンドを送ることで 結果を得ます
友人にアボカドトーストの作り方を 電話で教えるような感じです
まず必要な食材と道具を伝えます
その後パンを焼き アボカドを切るよう指示します こういった指示は少し面倒です 友人がパンを焼き忘れるなど 手順を間違えると― 結果的にすべてが台無しになります
次に宣言型でアボカドトーストを 作ってみましょう
宣言型コードは欲しいものを 記述して結果を得ます 作り方は誰かが皆さんのために 考えてくれます
アボカド職人にアボカドトーストを 注文するようなものです
カリフォルニアには アボカド職人がたくさんいます
皆さんがやることは 欲しい物を伝えるだけです
カスタマイズの指示もできます
やるのはそれだけ 専門家が作ってくれるので 品質も保証されています
SwiftUIではコードの専門家が 皆さんをアシストしてくれます 関係性をエンコードする 構造体を初期化することで ビュー間のヒエラルキー関係を コードで宣言します
SwiftUIが皆さんのビューを訳すという 大変な仕事を請け負い それを画面に結果として反映します
これについては さらに説明が必要ですが まずはコードの シンタックスに慣れましょう 最初はコンテナビューです
これはコンテンツである他のビューとの 組み合わせで宣言されます
contentViewはViewBuilderという 特別なクロージャの中で宣言されます
例えば 先ほどお見せしたVStackは このコンテナの一種です
ViewBuilderはクロージャのボディに 宣言型コードが書けます addSubviewのようなファンクションを 呼び出さずに クロージャの中でコンテンツを リストできるのです
この働きをもう少し知るため 実際のAPIを見てみましょう
クロージャとして定義された コンテンツのパラメータは ViewBuilderの属性になっています この属性のクロージャは Swiftコンパイラによって すべてのコンテンツを表すビューを返す 新たなクロージャーに置き換えられます
これは短いコードを書くための Swiftを使ったSwiftUIの一例です
VStackのビューにはコンテンツや 他のパラメータも取れます 例えばVStackでコンテンツを 端に寄せて並べるようにも構成できます デフォルトの中央並べではなくです
パラメータを一緒に使うことで 自然なシンタックスが作れるのです 中括弧や字下げを使えば コンテナビューや その中のコンテンツの構成を 差別化できます
多くのコントロールもコンテナなので シンタックスに従います
このアプリケーションの場合 各コントロールは目的を記述する ラベルを付けてTextを定義します
こうしたTextだけでなく 多種多様なビューも加えられます それについては のちほどお話ししましょう
シンタックスにある$マークは ToggleやStepperの 引数の前に付けるものです 先頭の$マークは コントロールに単なる値ではなく― バインドを渡す指示を出しています バインドとは?
この例ではStepperは 現在の命令を追跡する― 継続的ステートに依存しています ステート属性を使って 命令のためのプロパティを宣言します SwiftUIはこの属性の プロパティを見つけると 裏で自動的に 継続的ステートを作って処理します そしてプロパティを通して ステートの値を出します
この場合 ステートはすべての命令情報を表す― 自身で定義した構造体を含みます
このステート内のデータに 読み書きだけをする場合は プロパティに直接 読み書きすればいいので簡単です Stepperのラベルを作るために この方法を用いました
しかしStepperは ボタンがタップされた時も ステートの編集が必要です そこで$マークを先頭に付け バインドを Quantityプロパティに渡します 読み込み専用の値を 渡すのではなくです
バインドはビューに 他のビューのステートを編集する― 管理リファレンスともいえます
ステートとバインドまたデータ従属性の 管理について知識を深めたい方は Data Flow Through SwiftUIの セッションをお勧めします
しかし覚えておいてください ステートのようなある種のデータ依存を 表すプロパティの属性については SwiftUIが裏で皆さんに代わって 管理してくれるということです
また$マークのあるシンタックスは たいてい他のビューに バインドを渡すことを意味しています
アプリケーションの例に戻ると まだ重要なシンタックスが残っています 一番上にタイトルのフォントが 設定してあります
ズームしましょう
先ほどTextを初期化しました
これもSwiftUIのビューの1つです
次にfontと名付けられたテキストで メソッドを呼び出し それをシステムに定義された テキストスタイルに渡します この種のメソッドはSwiftUIでは モディファイアとして知られます これは既存のビューから 新たなビューを作るためのメソッドです
説明します
これはモディファイアを持たないUIです この場合タイトルはデフォルトの フォントでレンダリングされます
この時のビューのヒエラルキー図が こちらです VStackにTextが含まれているだけです
テキストがモディファイされると 既存のテキストをラップする― 新たなビューが挿入されます これにより SwiftUIが新しいフォントに レンダリングしてくれます
モディファイアは 連結して使うこともできます 例えばforegroundColorを加えると テキストの色が変えられます フォントモディファイアをラップする ビューがもう1つ加わりました
ビューのヒエラルキーが あっという間に大きくなりました UIプログラムをよく使っている人は― 危険を感じ始めているでしょう 我々はビューのヒエラルキーを 最小にすることで パフォーマンスを最適化するよう 訓練されてきました
しかし今書いているのは 宣言型コードです SwiftUIはその専門家なのです 我々がビューで注文したものを 巧みにレンダリング結果として 表してくれます 複数のラッパービューで テキストをラップする必要があっても SwiftUIが裏で効果的なデータ構造に 変えてくれるのです そしてレンダリングシステムで 使えるようにしてくれます パフォーマンスの影響を心配しなくても モディファイアを連結する シンタックスで多くの恩恵が得られます
例えばモディファイアの連結により― ビジュアルエフェクトの 決定順序が守られます
ここに背景が緑色のテキストがあります テキストが少し窮屈な感じなので 周りにパディングを加え 背景を大きくしてみましょう
パディングのモディファイアを加えると 新たなビューが加わりました 画面はそのままです
パディングはあるのですが 見えないだけです バックグラウンドモディファイアは テキストをラップしているだけなので パディングはバックグラウンドの外で 適用されます
これを直すにはテキストとパディングの 両方をラップするよう バックグラウンドモディファイアの 位置を変えるだけです
アプリケーションに戻って 結果を見ましょう パディングとバックグランドは 別々のモディファイアではなく テキストにあるプロパティだと 想像してください その場合どんな命令が 適用されたか知る方法はなく 試行錯誤したり 資料を読むしかありません しかし モディファイアを連結することで 命令を明確にできます カスタマイズも非常に簡単です
モディファイアのもう1つの利点は ビュー間でシェアできることです ここでは異なる種類の コントロールを増やすために 不透明度エフェクトを適用しました 個々のコントロールではなく スタック全体に― そのエフェクトを 採用することもできます 個々のビューが不透明度プロパティを 定義する必要はありません つまり 簡潔で的を得た インターフェイスにできるのです これはSwiftUIの一般原則です
1つの目的のためだけの小さいビュー こういったシンプルなビューは 理解しやすく メンテナンスも簡単です 小さいビューを作っておけば それを組み合わせることで 大きく複雑なビューが作れます
SwiftUIフレームワークは 小さな単位の組成を重視しています 皆さんもこの方法で コードを組み立ててださい
このテキストのような 単純なものから始めましょう それをモディファイして より良くしていくのです それを組み合わせることで すばらしいものが構築できます アボカドトーストが良い例です 皆さんがSwiftUIを使って どんなアプリケーションを作るのか 早く知りたくてたまりません
しかし それにはカスタムビューの 使い方の説明が必要です また新たなものを作ってみましょう
このアプリケーションで 過去のオーダー履歴を見たいです デザインしてきました 注文が要約された簡単なリストです 選んだトッピングを表す アイコンもあります
コードも書き始めているので 順番に見ていきましょう 最初にOrderHistoryという 新しいビューを宣言しました ビュープロトコルに従う構造体です 次へいきます
入力プロパティは 過去の注文のコレクションである previousOrdersだけです
ビューにはコンテンツを返す bodyという計算型プロパティがあります 計算キーワードはSwiftの機能を使い 自動で戻り値の型を推測してくれます
bodyプロパティは 履歴をマッピングすることによって コンテンツを生成するリストを 新しいビューのコレクションに返します その際は追跡型のViewBuilderが 使われます
このコードを理解しましたね なぜSwiftUIはこのような形で カスタムビューを定義するのか 詳しく説明していきます
ビューはどのように ビュープロトコルに従う構造体なのか? UIKitやAppKitユーザは スーパークラスを継承するビューに 慣れていることと思います プロトコルに準ずる 構造体では定義しませんよね
例えばUIKitのカスタムビューは UIViewのスーパークラスを継承します UIViewはalphaなど 一般的なビュープロパティの ストレージを定義します
UIKitでOrderHistoryを 作ることを想像してください カスタムビューはUIViewの ストアプロパティを継承します さらにカスタムのビヘイビアに対し 多くのプロパティが追加されます
SwiftUIはどうでしょう?
SwiftUIは同じように 一般的プロパティを表すものですが 個々のモディファイアを使って行います バックグランドを 不透明にした時のようにです
モディファイアは 独自のビューを作ります つまりプロパティに対するストレージは 個々のビューに継承されるのではなく 各モディファイアビューの ヒエラルキーにまたがって配分されます これによりビューは軽量になり 特有の目的のために ストレージを最適化できます
ビューがプロトコルになれば すべてのビューがストレージ テンプレートを持つ必要がなくなります
しかしビュープロトコルの 本来の仕事は? ビューのコンセプト定義を 思い出してください
ビューはUIの一部分を定義します そして小さいビューを組み合わせて 大きなビューを作ります
これがビュープロトコルが行う すべてです ビューヒエラルキーの一部分を定義し それに名前を与えることで アプリケーション全体で構成され 再利用されるのです
各具体的タイプのビューは bodyプロパティのコンテンツを表す 他のビューのカプセル化です また プロパティで表されるビューを 作るためのインプットでもあります
実際のプロトコルは 違う種類のビューを返す― 1つのbodyプロパティを定義します
この定義を見ているうちに 再帰の一種ではないかと― 思い始めた人もいるでしょう
あるビューが他の種類のビューと同様に bodyとして定義されていたら ビューはそのbodyを 他の種類のビューと定義づけます
これは永遠には続かず どこかで終わります
SwiftUIが多くのプリミティブビューを 提供することでこれを可能にします 独自のコンテンツを持たない―
他のビューが作られる際の アトミックブロックとしてのビューです
先ほど見たTextやImageも プリミティブビューです
SwiftUIはColorやShapeを 書くためのプリミティブも提供します Spacerのような レイアウトプリミティブもです
SwiftUIではプリミティブビューで 洗練されたドローイングができます 詳細はBuilding Custom Views in SwiftUIのセッションで学べます
ここではTextを使います しかし実際にはリストは 各列と分けるディバイダとして プリミティブビューの中に加えます
カスタムビューもクラスの代わりとなる 構造体として定義されます SwiftUIではビューがどのように 宣言的に定義されるかに戻ります この場合ビューは 継続的オブジェクトではありません イベントベースの命令型コードで アップデートするものではないのです
インプットのファンクションとして 宣言的に定義されます
インプットが変わる度にSwiftUIは アップデートされたビューを フェッチするためbodyプロパティを 再度呼び出します
ここで使っているリストは― 宣言型コードの効果を表す すばらしい例です previousOrdersのコレクションが 変わると― SwiftUIは新旧のリストを比較します そして効率的にレンダリングの結果を 画面にアップデートします
例えばアプリケーションを クラウドと同期させているとします 私はアボカドトーストのデータを 自分のすべてのデバイスで 見られるようにしたいのです 他のデバイスが履歴に注文を加えたり 削除したりすると何が起きるか?
右を見るとSwiftUIが自動的に コレクションの変更を察知し― 適切なデフォルトのアニメーションで レンダリングしてくれています コードを追加することなく 自由に使える機能です (拍手) すばらしいですね
皆さんは継続的レンダリングの ステートを管理する必要はありません bodyプロパティにある 現在のデータに基づき ビューに新たな値が生成されます
SwiftUIが皆さんに代わって 2つのバージョンの間で 必要な変更をしてくれます
これが宣言型コードの大きな利点です
残りのOrderHistoryビューを 作りましょう デザインでは注文に 塩やレッドペッパーなどの トッピングのアイコンがありました まず塩のアイコンを出します 最初にHStackを加え TextのあとにSpacerを入れます 塩のトッピングがある時のみ SaltIconビューを出すようにします
先ほどお話ししたようにコードには ViewBuilderシンタックスがあります ifステートメントでビューをスタックに 入れるべきかを宣言的に定義すると 自然なコントロールフローになります
宣言型コードで ifステートメントを使うのは 非常に自然なことです ビューに条件コードを書く方法は 他にもあります 結果を正しく画面に出すには 適切なツールを選ぶことが重要です 例を挙げて説明しましょう
この画面では 通常と反転のAppアイコンを 用意しました
最初のパスはflippedステートを取る カスタムビューです そして反転モディファイアを 条件付きで適用します
しかし実際に反転させると 見栄えが良くありません
これは2種類の異なるビューを 切り替えるコードになっているからです 反転モディファイアに ラップされたビューと Appアイコンのビューです
ビューは追加や削除が行われると フェードイン/アウトするので 見栄えが悪くなるのです
きれいにアイコンを回したい場合は rotationEffectモディファイアで 1つのビューを定義します そして条件付きのインプットにします
モディファイア内で定義することで 見やすいアニメーションになります 自然に回転していますね 条件は極力 モディファイアに 入れるようにしてください そうすればSwiftUIが 適切なアニメーションを作ってくれます
先ほどのifステートメントは ヒエラルキーからビューの追加や 削除を行う際に有効です
OrderHistoryビューが 少し大きくなってきました この辺りで小さく分解していきましょう Listの各列をカスタムビューに 入れていきます
まずOrderCellという カスタムビューを作ります
このビューのbodyは OrderHisotryビューのListにあるので これを移動します
OrderCellにはbodyを生成する インプットデータに加え それを表すためのプロパティも必要です
最後にListの各列に対する 新たなビューのインスタンスを作ります
UIを小さい塊に分解し コードを新しいビューに組み込むのは 非常に簡単でしたね また宣言型コードでは新たなラッパーを 加えることは実際上自由です なぜならSwiftUIが裏で最適化 してくれるからです
これからは納得のいく方法で コードを組み立てるか 最適なパフォーマンスを得るかで 妥協する必要はありません (拍手) 最後にレッドペッパーのアイコンを 完成させましょう 先ほどと同じく 条件を1つ加えるだけです しかしあまり スケーラブルではありません 新たなトッピングが加わったら コードにも新たな条件が必要です しかし orderデータから 条件付きでアイコンのコレクションを 生成できたらいいですよね?
これにはForEachビューを使います ForEachにもデータのコレクションと 各データアイテムをマップする ViewBuilderがあります ただしForEachは ビジュアルエフェクトを加えません その代りコンテンツを コンテナに加えます
これならOrderHistoryが 追加のトッピングにも対応してくれ コードの追加の必要がありません
卵のアイコンも追加できます
この10行程度のコードに これほどの機能があるなんて すばらしいですよね さらに驚く点は コードすべてを書く必要がないことです
SwiftUIは自動的にデータを 変更してくれ デフォルトで アニメーションも挿入してくれます
またDynamic Typeにも適用されます ダークモードでもコードを加えずに すべてのサポートが得られます
(拍手) すごいことです SwiftUIを使えば短いパスで すばらしいアプリケーションが作れます
ここまではSwiftUIでの カスタムビューの構築の仕方でした 次は同僚のテイラーに話してもらいます SwiftUIが提供する革新的な ビューの利点についてです ありがとう (拍手) ありがとう
こんにちは マットにはオーダーフォームと 履歴画面について話してもらいました よくご存じのアプリケーションとは かなり違いましたね これまでのVStackのコントロールは― 右側のようなUIだったと思います 大きな違いは コントロールの周辺にあるコンテナです
標準的なリストスタイルです SwiftUIではこれをFormと言い― VStackのようなコンテナです ただし異質のコントロールの セクションを作るために作られ どのプラットフォームでも 同様のルック&フィールが得られます
必要なファンクションは 定義しておきました title Toggle Stepper Button ここでコンテナを既存のVStackから Formに変更することで コンテンツを分ける セクションを簡単に加えられます コードはUIの結果を 反映するために継続されます コントロールのコアな定義は 変わらないので コードを変える必要もありません コンテナをVStackから Formに変えるだけで コントロールの結果が 自動的に適応されます 背景やコントロールの境界線だけでなく ボタンのスタイルまで変わります SwiftUIはレンダリングする エレメントにまでサポートするので 我々はアプリケーションの機能に 集中することできます
微妙な変更があっても この画面では見えません アライメント パディング 文字修飾は ボタンの周辺でなされますが プレスステートでは このタイプのUIで使いやすい― 特別なフルスクリーンとなります ボタンはずっと 同じ明確な定義を表します
他のコンテキストや プラットフォームでもこの定義は― 幅広いルック&フィールを持ちます
ボタンは他のビューと同じく 固有の構成能力を持っています もちろんラベルはテキストだけでなく イメージにも拘束されます イメージやテキストの 明瞭なVStackまで― あらゆるタイプのビューとして 定義できるのです (拍手) この固有の構成能力は 幅広い可能性を持ち― ボタンを2つの基本的な プロパティとすることもできます actionが実行された時に ラベルがその動きを記述します これがボタンのAPIです ボタンをカスタマイズする方法は この2つだけではありません 先ほども見ましたが― コンテキストやモディファイアにより もっと豊かなビヘイビアを加えられます 無効ステートからボタンのスタイル macOSのサイズ管理に至るまで コアな定義とその適応性により どんなタイプのボタンも作れます 異なるプラットフォームに 多様なボタンがあります 見え方だけでなく双方向性も様々です 例えばスイッチコントロールや Siri Remoteのクリックやタップなどです これらはすべてアクションやラベルで 表すことができます
ボタンだけでなく すべてのSwiftUIのコントロールには 豊かなビヘイビアを もたらす機能があります コントロールは見え方だけでなく その目的や役割を表します そのため状況に応じて 違うコンテキストや プラットフォームでも使えるのです 明確な役割を伝える より小さなAPIを持つことができ コンテキスト毎にコントロールを持つ 必要がなく少なくて済みます
しかもこれにより 有益なカスタマイズができ ボタンの見え方を 定義し直す必要はありません
この適応性が 単純なスタックのコントロールから 標準的な ルック&フィールに変換してくれます こういった適応性はApple Watchなどの 他のプラットフォームにも 対応しています いつでもトーストを注文できます
他にもトグルのコントロールがあります SwiftUIのトグルは単なる リテラルなスイッチではありません これはどんなプラットフォームでも 使えます またボタン同様 トグルにも 2つの基本的プロパティがあり オンオフの感知とトグルの目的を 記述するラベルがあります これも構造自体に反映されます
ボタンとの大きな違いは アクションは起こさず ブーリアン値にバインドします このバインドは直接ステートや モデルに読み書きを接続し― トグルが反映やアップデートを行い― 値をプルしたのちにモデルに設定します 皆さんの代わりにやってくれます (拍手)
トグルなどのコントロールは 他にも適応可能です UIをビジュアル体験に使ったり 他の用途に使ったりするでしょう まったく同じUIをです 視覚障害のある人は VoiceOverの音で ナビゲーションを操作します また聴覚障害のある人は次の音で VoiceOverを起動します “ボイスオーバー オン”
VoiceOverはシステム全体の機能で 皆さんのUIでもフォームを切り替えて 使うことができます トグルや他のコントロールは 目的に応じて定義され 人が解釈可能なラベルを含むので 自動的にこれらの機能に対応できます VoiceOverを使って トグルを操作すると… “塩を選択 スイッチボタンをオンに” “ダブルタップでトグルをセット” 同じラベルを反映することができます ラベルがテキストでない場合も同様です もしイメージの名前が 説明不十分であれば 直接イメージの隣に 明瞭なラベルを提供できます
もちろん完全なカスタム… (拍手) 興奮しますよね (拍手) もちろん完全なカスタムビューでも ラベルモディファイアを使って ラベルを提供できます VoiceOverに加え他の機能も使えます 音声コントロールの最新版です “タップで塩を選ぶ”と言うと UIがそれに対応します こうした異なるテクノロジーを使って 誰もが使える アプリケーションにしてください SwiftUIがお手伝いします
今年はアプリケーションを アクセシブルにする詳細について 有益な話があります
ここまでDynamic Typeやダークモード アクセシビリティといった インターフェイスの構築を行いました 少しのカスタムオプションを 加えただけです とは言え トースト職人のレパートリーは幅広く パンの種類も違えばアボカドの切り方 様々なトッピングもあります
このようなオプションの追加には macOSを活用することができます ここから トーストの注文ができたらどうでしょう
macOSの画面には トグルやステッパーやボタンといった 既存のコントロールがあります 加えてパンの種類や アボカドの切り方を選べる コントロールが追加されています
これはピッカーコントロールの例です ピッカーはオプションから 1つの値を選ぶものです
他のコントロールより少し複雑で― コアプロパティは3つあります 選択できるオプションには 現在のselectionと ピッカーの目的を記述する labelがあります
トグルがプロパティにあるように selectionはバインドなので 直接modelerステートに 関連付けられます このバインドの型は各オプションに 紐づいたタグの値に相当します オプションが選ばれると タグの値はselectionに書き戻され モデルに戻ります
macOSのピッカーはポップアップとして 表示されるとは限りません ピッカーには2つの異なる スタイルがあります ポップアップとラジオグループです
SwiftUIがデフォルトのスタイルを 自動的に提供する間 コントロールは継承的にスタイルを カスタマイズします デフォルトやカスタムビルド 両方のスタイルにです この場合オプションは2つなので デフォルトのスタイルを無効化して ラジオグループを使用します
スプレッドについても同じです 4つだったスプレッドの選択肢は あっという間に数を増やしました
ピッカーを構築する時は― 1つずつ記述するのは避けたいですよね UIにラジオボタンを 使わないのと同じです
すでにForEachはご紹介しましたね 各オプションはビューなので ここでもForEachを使います
この方が効率的です このようにspread.nameとspreadの 新しいオプションを作ります
つまり… (拍手) ピッカーはmacOSだけでなく iOSではホイールスタイルが 使われています Formの場合 SwiftUIは自動的にピッカーを適応し 非常に一般的な スタイルを採用します
スプレッドのPickerは ナビゲーション列によって表され labelと選択された値を表しています Spreadをタップすると すべての選択肢が表示され 選択すると元に戻ります (拍手) 重要なことは シンプルなピッカーを作るだけで SwiftUIがすべて行ってくれます (拍手) 残り3つのピッカーも構築しましょう macOSと同様に アルティメットコントロールがあります ホイールスタイルを使うこともできます
この時点でも すばらしいアプリケーションですが トーストを注文できるだけのものです どんなアボカドトーストが 一番なのか 家族と議論になるかもしれません
右側のフォームは 先ほどと同じ構成で― コードも同じです 同じ構造体とコントロールを 使っていますが 違いは自動で適応するかです ここではトグルが オン/オフボタンになっています
これはSwiftUIで非常に重要な点です
一度コンセプトが分かれば どこにでも応用できます SwiftUIはコードを実行する 手段ではなく コンセプトを学べる フレームワークです 異なるコンテキストや プラットフォームで使えます モディファイアや ViewBuilderシンタックス ForEachや高レベルの コントロールまでもあります
こうした知識を活用できるのが 少しプラットフォーム的な contextMenuの構築です
.contextMenuはモディファイアを使って ビューに紐づけされます モディファイアはメニューコンテンツの 定義にViewBuilderを使います メニューを見ると いくつか見慣れたものがあります クリックでアクションが起き ラベルがそのアクションを記述したり 特にオン/オフの切り替えは よく知っているものです ButtonやDivider Toggleといったコントロールを使って コンテンツが構築されていますね 自動的にルック&フィールを macOSのメニューにも引き継ぎます ホバーやジェスチャ管理 ハイライトやスタイルなどです
SwiftUIのコントロールが 特別だと お分かりでしょう コントロールはビジュアルよりも 目的や役割 モデルに基づいて定義されます つまり 過去の コンテキストに再活用でき コンテキストなどに基づいて 適切なルック&フィールが決まります 同時にカスタマイズも可能で ラベルやオプションのビュー スタイルの変更が可能です デフォルトやカスタムビルドの スタイルも同様です もちろんアクセサビリティの サポートも組み込まれています
先ほどマットがビューに 追加のビヘイビアを課すために モディファイアを 使った例をいくつか挙げました コントロールでも同じことができます
iOSユーザにはお馴染みですが UIの色を変えるには システムコントロールが関係します アプリケーションに適用する時は― accentColorモディファイアを ビューの一番外側に採用します するとヒエラルキー全体に継承されます
コントロールの無効には disabledモディファイアを使います 注文がない時は 注文ボタンを無効にします コントロール全体を 無効にする場合もあるでしょう トーストのネットワークに 接続できない時などです すべてのコントロールを 無効にすべきですが コントロールを追加している時は エラーが起きそうです しかしモディファイアの位置を 移動させれば Form全体に適用できます accentColorと同じです (拍手)
すべてのコントロールは 無効になりました この適応性と継承性のあるビヘイビアは 非常に有効で― 単純な値型ビューを使ってきた 我々には驚くべきことです 内部での動作を見てみましょう
これらは環境の上に構築されていて― すべてのコンテキストで構成されます これらはグローバルステートとして とらえていたものです 祖先オブジェクトに 到達する必要がありました しかし環境にはすべてが含まれていて 使いたい人は誰でもアクセスできます また各ビューはその親から環境を 継承します 例えばアラビア語で実装する場合 ルートの環境は 右から左へと進みます すべてのビューに継承されます しかし任意でサブツリーのビューを 上書きすることもできます メディア再生のコントロールは 左から右方向にしたいので― 環境モディファイアを使い 方向を修正します
環境はプレビューを見る際にも 非常に役立つテクノロジーです 様々なコンテキストを 見ることができます 個々のユーザに適応したプレビューです
環境が多様なシステムビューに 自動的に作用し カスタムビューでも 使えることが分かりました 次はコントロールを見ていきます トーストの適切な場所に 卵を置くためのコントロールです これは2つの単純なZStackの イメージでできています トーストの上にdragGestureで もう1つイメージを配置します タップ&ドラッグで卵を移動できます
卵が在庫切れの場合など 卵のビューを無効にする必要があります ただし dragGestureを使っているため 自動で無効になります 卵をドラッグしようとしても 動きません 無効にされるビジュアル フィードバックも必要です これはとても簡単です isEnabled値に関連付けられる 環境プロパティを加えれば その値を使うことができます 例えば無効にされた時に 全体的に彩度を下げることができます
無効が解除された場合 SwiftUIはビューのbodyを呼び戻し 有効のステートに レンダリングし直します ここでもSwiftUIは自動で環境の 依存関係を管理するので ビューの関係性を表すだけです 変更を監視する必要がありません
多くのコントロールについて 学んできました しかし重要な点を まだ説明していません 画面間のナビゲーションです 注文フォームや卵の配置のピッカー 注文履歴がありますが 注文フォームから始めます フォームのタイトルが不自然なことに お気づきですか? 一般的な ナビゲーションバーではありません そこでまずNavigationViewの OrderFormをラップします NavigationViewは ネスト化された詳細な情報を含む― 各画面間のナビゲートをするものです iOSではChromeの ナビゲーションバーにも加えられます これでNavigaionBarTitle モディファイアが使え タイトルが太字になりました このモディファイアは少し特殊で NavigationViewの祖先により 訳された情報を提供します ビューヒエラルキーのフロー情報を 下から表す説明はしましたが これはプリファレンスを使って フロー情報を下から上へ表すものです 詳細はお話ししませんが のちほど似た例をお見せします
次に加えたいのは 注文に卵がある時のサポートです ここにToggleを加えます 卵が選択された際は EggLocationPickerに移動する ナビゲーション列を加えます コードを見てみましょう Toggleが注文の 卵のあるなしを調べます その次に 任意でナビゲーション列を含む ViewBuilderの条件文を使います これはアニメーション化された バインドをToggleに提供します スイッチをタップすれば― ナビゲーション列はFormListに アニメーションで挿入されます ナビゲーション列の表示も 非常に簡単です 宛先コンテンツを提供する特殊な― NavigationButtonを使い 双方向性がある時にナビゲートします NavigationButtonは自動的に 正しいルック&フィールにしてくれます ディスクロージャインジケータを 後縁にするなどです ビューは軽いので ここにEggLocationPickerを作れます SwiftUIはビューが実際に 現れた時のみレンダリングします
EggLocationPickerの中の EggPlacementViewを使って ナビゲーションバーをカスタマイズし 現在のステートをタイトルに反映します またnavigationBarItemsに trailingも加えます これまで学んできたように アイテムもビューなので Buttonを提供するだけです きちんと動くナビゲーションが 作れました
次はOrderHistoryです これをナビゲートしたくてもフォームの ネスト化された情報ではなく まったく異なるセクションです この場合TabbedViewを使います NavigationViewと同じように TabbedViewでフォームをラップし OrderHistoryにもう1つ子を加えます どちらもタブバーへのラベルの付け方を TabbedViewに記述する― tabItemLabelモディファイアを 持っています
OrderHistoryを簡単に見ました この時点ではOrderHistoryの内容は 非常に単純です これを履歴リストから ナビゲートする― さらに詳しい情報にしていきたい ですよね ネスト化やもっと詳細な情報については 先ほど見たように NavigationViewやボタンを使えば―
OrderHistoryのリストのコンテンツを 代えることができます OrderDetailで リストを埋め込み表示するのではなく この新たなOrderDetailを NavigationButtonの宛先にします 追加のコンテンツをナビゲートできる データドリブンのリスト化は簡単です これはiPhoneでは有効ですが iPadで使うには Split Viewで Master-Detailの設定が必要です 1つのrootViewに積み上げていく iPhoneのNavigationStackと違い ナビゲーションが2つあります Masterは Detailにコンテンツを積み重ねます
iPhoneでは1つのRoot Contentで NavigationViewが正しく動作しますが 本来は2つのコンテンツがあります OrderHistory MasterとDetailViewです 何も選択されなかった場合の プレースホルダとして OrderDetailPlaceholderビューが 使えます これはNavigation Buttonが OrderHistoryと双方向である時 自動的にOrderDetailに プッシュされます iPadや大きいクラスでも 期待どおりに動いてくれます 小さいサイズのクラスは自動的に 1つのNavigationStackに畳みこみます
もちろんmacOSでも Split Viewを使うことになります しかし一度書いただけで どこでも実装できるわけではなく macOSの情報密度が高い場合などは 留意が必要です しかしSwiftUIはSpilit Viewの テーブル列の高さなどを 自動でプラットフォームの 標準的ルック&フィールにしてくれます 一度異なるコンセプトの使い方を学べば どこでも適用できます 皆さんは刺激的なカスタマイズに 時間を割くことができ すばらしいアプリケーションの 構築ができます
これである程度の内容は カバーしましたが より詳細についての セッションがたくさんあります ステートとバインドの変え方 双方向のコントロールの話をしましたが SwiftUIのデータフローを 一緒に考え直すことで― データドリブンなUIに アップデートできます カスタムビューも構築しました SwiftUIのカスタムコントロールでは レイアウトやグラフィックや アニメーションの― 革新的使い方を すばらしいデモで見せてくれます すぐにでもSwiftUIが 使いたくなったり 既存のアプリケーションに 統合したいでしょう それもできます SwiftUIはシームレスに既存の ビューやモデルと統合できます それについてのセッションもあります SwiftUIはすべての人に アプリケーションを使ってもらえる― 画期的なものです 熟慮すべき点はあると思いますが このセッションを糸口にしてください 最後になりましたが SwiftUIは革新的技術です プラットフォームをまたがった シェアも簡単にできます SwiftUIはすべてのデバイスで 追加された詳細をシェアするため どんなプラットフォームでも 優れたアプリケーションを作れます 他のデバイスを使った詳細は watchOSのセッションや What's New in Swiftで紹介します ご清聴ありがとうございました 楽しめました (拍手)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。