ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
SwiftUI Appへのリッチなグラフィックスの追加
SwiftUIでグラフィックを活用する方法について確認しましょう。キーボードセーフエリアを含むセーフエリアの利用からはじめ、オンスクリーンキーボードに重ならない、端から端まで広がる美しいグラフィックをデザインする方法を紹介します。また、簡単にカスタマイズできる背景やコントロールを作成するために、SwiftUIで使用できるマテリアルや鮮やかさについて確認し、drawingGroupなどのグラフィックスAPIとまったく新しいCanvasについても説明します。これらのツールにより、SwiftUIで完全にインタラクティブで割り込み可能なアニメーションやグラフィックスをこれまで以上にシンプルにデザインできます。
リソース
- Add Rich Graphics to Your SwiftUI App
- Adding interactivity with gestures
- Composing SwiftUI gestures
- GestureState
関連ビデオ
WWDC21
-
ダウンロード
私はジェイコブです ようこそ 「SwiftUI Appへのリッチな グラフィックスの追加」へ 私は同僚と グラデーションを作成する Appに取り組んでいます 今年 私たちのチームは “色”に注目しています すでにほぼ実装は 完了しています リッチグラフィックスを 追加して完成させましょう Appを カスタマイズしていくと いくつかの 異なる領域に気づきます セーフエリアのカスタマイズ 新しいフォアグラウンドスタイル 新しいリッチなマテリアルセット Canvasを使った描画 新しい強力なビューなどです それでは始めます Appの 中身を紹介します グラデーションの ライブラリで 様々なグラデーションを 見ることができます このグラデーションの 何かに惹かれました 具体的に何かは 説明できませんが グラデーションを編集して 色の変化を 止めることもできます
新たなグラデーションを 追加することもできます
これらのグラデーションを ビジュアライザーで 使うこともできます 1つずつ解説していくので 後で説明します
ここでは グラデーションの 詳細表示に注目しましょう 機能的ですが 画面の大きさに対して かなり小さく 空白が多いです グラデーションを 主役にしたいと思います 早速 Xcodeで 編集してみましょう
これがメインの詳細表示で 編集モードにも使われます 「Editing false」 から始めましょう 編集モードについては 後述します フレームを削除して なるべく多くのスペースを 使うようにしたいです
グラデーションが すべての高さを 占めているので このスペーサーは もう必要ありません
これをZStackに変更して このグラデーションの上に コントロールを配置し さらに先に進むことが できます
ZStackを見たことがない 方のために説明すると ZStackは要素を 隣り合わせではなく 重ねて配置します 編集コントロールを 一番下に移動しましょう
そして グラデーションではなく コントロールにのみ パディングが必要です これを移動しましょう
パディングを削除しても グラデーションの上下に 空きスペースがあるのは なぜでしょうか? デフォルトでは SwiftUIはコンテンツを セーフエリア内に配置し ホームインジケーターや 表示されているバーなど 視界を遮ったり 切り取ったりするものを 避けます セーフエリアは ビューが表示される 一番外側のフルエリアから インセットされた領域として 表わされます セーフエリア内の コンテンツは 自動的に 適切なインセット内に レイアウトされ コンテンツが見えなくなる エリアを回避します セーフエリアは SwiftUIが キーボードの下に コンテンツを 描かないようにするための 方法でもあります このAppでは コントロールが自動的に キーボードの邪魔に ならないように表示されます
これも同様です 詳しく見てみると 複数の異なるセーフエリア があります 最も一般的なのは コンテナセーフエリアです ビューが表示される コンテナによって駆動され バーやデバイスクロームなどが 含まれます さらに キーボードを 回避するための キーボードセーフエリアが あります キーボードセーフエリアは 常にコンテナの セーフエリア内の領域で あることにご注意ください キーボードに加えて コンテナのセーフエリアと 同じエリアで コンテンツを 安全に保護します セーフエリアを 除外することもできます 通常 これは必要ありません ほとんどのコンテンツが セーフエリアにあるため クリップされないように なっています このままで安全です 背景やその他のコンテンツを 端から端まで 完全に表示したい場合は セーフエリアを 無視してもいいでしょう このコードを使用して すべてのセーフエリアから オプトアウトすることも キーボードのセーフエリア のみ除外もできます リニアグラデーションに ignoresSafeAreaを追加して 縁なしの状態で 表示しましょう
Edit ボタンはグラデーション 上では見にくいので 下端のセーフエリアのみを 無視しましょう
グラデーションのせいで 下のテキストが読めなくなる という 同じ問題に遭遇しないように 背景を追加しましょう
背景のカスタマイズに ついては後ほど説明します まずは最もシンプルな デフォルトの設定です ダークモードで自動的に変化する 白い背景が表示されます
この背景は自動的に セーフエリアを超えて 広がります このバージョンの背景と その動作は iOS15 と並行して リリースされたOSです その仕組みを 見てみましょう 最初にコンテナビューと そのセーフエリア について説明します そして コンテンツビューですが 読みやすさを保つために セーフエリア内に設置します 適用されるビューに 同じ境界を持つ背景を 単純に追加すると このようになります しかし ignoresSafeArea修飾子を 背景ビューだけに適用すると メインコンテンツはきれいに 安全に保たれたまま セーフエリアを超えて 拡大します 新しいbackground 修飾子は この動作を自動的に 生成します
背景に戻って カスタマイズを始めましょう 特定のスタイルを 渡すことができ 色やグラデーションなどの 他のスタイルに することができます
このAppでは あまり意味がありませんが パステルカラーのものを 見てみましょう
また シェイプを渡して この背景をクリップします 例えば 角が丸い長方形にします
カスタムシェイプを 使用すると 背景がセーフエリアから はみ出さなくなり コンテンツの境界に 一致しています このAppの背景に ぼかしを入れたいと思います 別の新しいAPIの Materialを使います 標準的な ぼかしのセットです
この背景を元に戻し 全体を占めるように しましょう
Materialは カラフルなコンテンツで 見せたい場所に最適です 超淡色から超濃色まで さまざまな素材が 用意されています どのような プラットフォームでも 適切なデザインを 自動的に表示します
ここでは淡い色彩の 素材を使用します
次にテキストを カスタマイズします ここでは名前が主要な 情報であることを示すため 色の数を少し 目立たなくしてみましょう
セカンダリの前景スタイルを 設定します
セカンダリコンテンツは 背後の色をブレンドする 「Vibrancy」という効果で 自動的に表示されます SwiftUIには この効果用の 特別なAPIはありません Materialコンテキストで セカンダリからクォータナリ スタイルを使用すると 自動的に発生します 先ほどのようにMaterialを使って 背景を明示的に追加した場合や コンテンツがサイドバーなどの システムコンポーネントの 中にある場合に Materialを追加すると 自動的に起こります
これらのスタイルは多くが 自動的に賢く振る舞います 鮮明にする効果を使わない ぼかしていない状況でも 自動的に正しい効果を 施します 色を設定すると 自動的に動作が変わり レベルに応じた 色のバージョンが設定されます 同じサポート機能で グラデーションなどの 基本的な前景スタイルを 設定することができます センス良く使って みてください 注意点としては 任意のテキストに適用される 前景スタイルは1つですが その範囲内で複数の色 を適用できます 例えば 文字列の変数置換を使って Textを埋め込んだり
colorsという単語に 赤のforegroundColorを 適用します 自動的に設定した赤色が 透けた色を 除外して表示されます
さらに重要なのは これらの前景スタイルを 使用すると 初めて埋め込まれた 絵文字が 正しく機能します
良い感じですね もう一度 編集モードを 試してみましょう
ほぼできています ぼかし効果の下でも 色が見えますね しかしよく見ると 正しく作動していない ようです 下までスクロールすると リストの一部がぼかしの下に 隠れてしまいます 何が起きているか 見てみましょう 飾りを取り除いて 関連するビューのみを 表示します
ビューを少し水平方向に スライドさせてみると バーがコンテンツの上に ZStackされていることが わかります 背面のすべてのビューを 見たいので これは 正しい動作ではありません
ここでVStackに 変更してもいいのですが ボカシの下にリストがないと 下にスクロールしても 色が透けて見えません リストの背景と スクロール可能な領域を バーの下に拡張したい のですが メインコンテンツは 拡張したくありません まさにこれが セーフエリアの目的です セーフエリアを このバーでインセットして 重要なコンテンツが 隠れないようにします ビューのセーフエリアを カスタマイズするために 新しい修飾子safeAreaInset を使用します メインコンテンツの上に バーなどの補助コンテンツを 追加できます ZStackを
safeAreaInsetに変更します
Edge: .bottomを使って
制御できるようにします もう一度確認してみましょう
ビューはほとんど 同じに見えます それでよいです セーフエリアを 無視しているからです
編集モードでは
ボカシの下でも スクロールできます 最下部まで スクロールしても 何も隠れていません 良いでしょう 次に Visualizerを 見ていきましょう
すでに作成されている Shapes visualizer から始めます
多数のランダムな形状の シンボルが表示され Appのグラデーションで 描画されています シンボルをタップして 拡大したり
背景をタップして シンボルの 位置を変更できます
SwiftUIアニメーションの デモにもあるとおり 常にインタラクティブで 中断可能です 再配置を続けたり
タップして図形を選択したり 選択を解除したり することもできます
コードを見ると グラフィックを描画する
一般的な手法を 使用しています GeometryReaderによって ビューのサイズを読み取って すべてのグラフィックを レイアウトし ZStackを読み取って 配置することができます
そしてボディの最後には、 drawingGroup修飾子 があります drawingGroupは SwiftUIに含まれる すべてのビューを 1つのレイヤーにまとめて 描画するように指示します これは これらのような グラフィック要素には有効ですが テキストフィールドや リストなどの UIコントロールには 使用しないでください
これは 今回のように 多数のグラフィック要素を 表示したい場合に 有効な手法です またdrawingGroupの 利点の1つは これらのビューの描画方法が 異なっていても Appの他の場所で 使用しているのと同じ機能を SwiftUIで 使用できることです
たとえば ここでは シンボルをタップするために 各シンボルにジェスチャが 適用されています また 選択を変更したり シンボルを再配置するときに 適用される アニメーションもあります これらのビューに含まれる アクセシビリティ情報も 通常どおり渡されます たとえば 各シンボルに対する アクセシビリティアクション のようにです しかし これらの機能をすべて サポートするためには 各ビューに その情報の保持と ストレージが必要です 要素の数が十分に多い場合は オーバーヘッドが 多すぎる可能性があります そのようなケースがあるので 新しいCanvasビューを 導入しました 次のビジュアライザーは 複雑なパーティクルシステムを 表示しますが まだ作成されていません 早速作ってみましょう Canvasビューを使って 描いてみましょう
Canvasが 描画されるたびに 実行される 描画コマンドを含む クロージャを 作ることができます UIKitまたはAppKitの drawRectに 精通している場合 ほとんど同じように 機能します このクロージャーにより 描画コマンドの送信先となる コンテキストと Canvas全体のサイズを 取得するために 使用できるサイズが 得られます 画像を描くことから 始めましょう
同じ画像タイプを使用して 作成できます SwiftUIの残りのコードで 使用しています
そして、コンテキストに 画像の描画を指示します
0,0で描画すると 原点を中心に表示され あまり目立たなくなります せっかくCanvas全体の サイズがあるので それを使って 真ん中に描いてみましょう
プレビューを ダークモードに変更すると わかることが1つあります
以前に見たのと同じ 前景スタイルを 使用しているため 画像が自動的に反転して 白で描画されます パーティクルシステムを 構築したいので この画像を もう数回描きましょう
このクロージャは 通常のコード用で ViewBuilderではありません したがって 通常の forループを使用できます
実際に見えるように 各画像を少しずらします
現在 この画像を 数回描画していますが 毎回同じ画像であっても コンテキストが解像して 現在の環境などに基づいて 評価する必要があります これを改善するには 画像を自分で解像してから 描くことです
同じ解像度の画像を 共有しているため パフォーマンスが向上し 解像度の高い画像を使用して 他のことも できるようになりました
サイズとベースラインを 求めることができます そのサイズを使用して それぞれの形を適切な量だけ シフトします
次に きらめきの後ろに 楕円を加えてみましょう 同じリージョンに描きます 双方を引き寄せるための フレームを出してみましょう
同じXとYの値を持つ CGRectを作成して 幅と高さにはImageSizeを 使って 幅と高さを調整します
そして 枠の中に イメージを描きます
各描画操作は順番に 行われるため 楕円を画像の後ろに 配置するには 最初に楕円を描画する 必要があります context.fillで 描くことができます
これはパスとシェーディングを 取ります 標準的なベジエ曲線を使って パスを作成できますが 次のようなヒントもあります 楕円のような図形を使って 与えられた長方形の中での パスを求めることもできます
もう1つの引数は シェーディングです これはパスを 埋めるためのものです 他のSwiftUI Appと 同じスタイルを使用できます シアン色を使いましょう
楕円です 画像とのコントラストが あまりありません それを修正しましょう グラフィックスコンテキスト には不透明度 ブレンドモード変換などの 描画プロパティがあります ここで 不透明度を設定しましょう このコンテクストが 今までとは 少し違った動きをする 分野を見てみましょう コンテキストに不透明度を 設定するだけで 期待通りの動作になります これはその後のすべての 操作に影響します
以前は 一部の描画操作にのみ 適用される グラフィックコンテキストに 変更を加えたい場合は, それらの操作を保存と 復元の呼び出しで 囲む必要がありました しかしSwiftUIの コンテキストでは コピーに変更を加えるだけです
これらの変更は 変更されたコンテキストで 行われた描画にのみ 影響します 元のコンテキストで行われた 描画は影響を受けません
イメージに 色を加えてみましょう
解像した画像でできるのは シンボルの描画方法を 制御するための シェーディング設定です
青を設定します
期待より暗い青です 描画しているときに 正しくブレンドモードを 使うと効果てきめんです ブレンドモードは 色の組み合せを制御します 特にここにある 半透明な色などです
画面を ブレンドモードにします 常に明るくなるように 色を組み合わせます 良くなりました
実行できる描画操作は 他にもたくさんあります GraphicsContextタイプを チェックして 可能なすべてを 確認してください シミュレーションのように するためには 実際に動かす必要があります SwiftUIには 時間の経過とともに 変化させるための ツールがいくつかあります アニメーションは 最も一般的であり 通常 変更を加えると 自動的に変化します 今年 新しい TimelineViewという 下位ツールを紹介します 時間の経過で起きる変化を 正確にコントロールしたい 場合に使います 変更したいビューを ラップするだけで TimelineViewを 使用できます.
更新の頻度を示す スケジュールを使用して 構成できます
タイマーなどの スケジュールもありますが 今回はアニメーションの スケジュールを使って 更新情報をすぐに 表示できるようにします
ディスプレイリンクを ご存知なら それとよく似た仕組みです 知らなくても大丈夫です 何を表示するか 情報を提供する タイムラインコンテキストが 渡されます
画像をアニメーション化 するために 使用する時間を 秒単位で引き出します
画像を回転振動させて みましょう 今から角度をつけます
remainderを使って 3秒ごとに ループさせてみましょう
それを120倍すると 360度になります.
そしてコサインでXの値を 得ます サインだったかな? 三角法を覚えていますか
その値を使って オフセットを変更しましょう
プレビューで見え方を 確認してください
良いですね 重なるとさらに明るくなるか 見てください スクリーンブレンドモード が稼働している状態です 次に インタラクティブ 機能を追加しましょう 個々のビューにジェスチャを 追加することで実行できる インタラクションを 確認しました Canvasを使用することの トレードオフとして Canvas内の個々の要素が 1つの図面に まとめられることを 覚えておいてください そのため 例えば個々の画像に ジェスチャを付けることは できませんが ビュー全体にはジェスチャを つけることができます 表示される輝きの数を 増やす機能を 追加しましょう 何個表示するかの設定を 追加します
最初は2個からです カウントを使って ループを制御しましょう
TapGestureを追加して カウントを増加させます
プレビューを更新しましょう
タップして 輝きを追加できます
Canvasを使う上で 大事なことは 1つのグラフィックであるため アクセシビリティで利用できる コンテンツに関する 情報がないことです アクセシブルにするために 標準的なaccessibility 修飾子を使って ビューに関する情報を 追加します
より高度なケースでは 強力な新機能である .accessibilityChildren 修飾子は ビューに関する アクセシビリティ情報を 生成するために使用する 任意のSwiftUIビュー階層を 指定することができます 「SwiftUIのアクセシビリティ: 基礎を超えて」を ご覧になってください
比較的簡単なCanvasの 使い方を紹介しましたが もっと複雑な使い方にも 対応できます 少し試してみましょう 同僚が書いてくれた シミュレーションコードは 同じように動作しますが より多くの要素が より面白いことをします 彼が送ってくれたファイルが ここにありますので ビューに貼り付けます
このコードも同じ構造です これですべての パーティクルを追跡し 時間の経過とともに 更新される 長寿命のモデル・ オブジェクトができました 同じTimelineViewとCanvas を使って コンテンツのアニメ化と 描画を行います モデルを新しい日付で更新し スクリーンの ブレンドモードを設定し 各アクティブパーティクルに 先ほどの楕円と同じように 描画するように 指示しています そして最後に 少し 複雑なジェスチャを使用して 同じ修飾子を適用します どのように見えるか 見てみましょう
定期的に新しい 花火バーストを作成します タップしてさらに 追加することもできます Appのグラデーションの 色を使った 楕円で作られています
Canvasでの描画の もう一つの素晴らしい点は watchOS tvOS macOSでも 動作することです 全SwiftUIプラットフォームで 利用できます これで Appが完成しました その過程で セーフエリアの操作と修正 前景スタイルを使って コンテンツの描画を 制御する方法 マテリアルを使ってぼかしや 鮮やかさを表現する方法 CanvasとTimelineViewを 使って 複雑なアニメーション グラフィックを作成しました みなさんの素敵な 作品を期待しています [音楽]
-
-
3:53 - Ignoring safe areas
// Ignore all safe areas ContentView() .ignoresSafeArea() // Ignore keyboard only ContentView() .ignoresSafeArea(.keyboard)
-
7:08 - Foreground Styles
VStack { Text("Primary") .foregroundStyle(.primary) Text("Secondary") .foregroundStyle(.secondary) Text("Tertiary") .foregroundStyle(.tertiary) Text("Quaternary") .foregroundStyle(.quaternary) }
-
7:35 - Purple Foreground Styles
VStack { Text("Primary") .foregroundStyle(.primary) Text("Secondary") .foregroundStyle(.secondary) Text("Tertiary") .foregroundStyle(.tertiary) Text("Quaternary") .foregroundStyle(.quaternary) } .foregroundStyle(.purple)
-
7:41 - Blue Gradient Foreground Styles
let blueGradient = LinearGradient( colors: [.blue, .teal], startPoint: .leading, endPoint: .trailing) VStack { Text("Primary") .foregroundStyle(.primary) Text("Secondary") .foregroundStyle(.secondary) Text("Tertiary") .foregroundStyle(.tertiary) Text("Quaternary") .foregroundStyle(.quaternary) } .foregroundStyle(blueGradient)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。