WWDC Quick Look 💓 By SwiftGGTeam
Add rich graphics to your SwiftUI app

Add rich graphics to your SwiftUI app

元の動画を見る

ハイライト

SwiftUIはiOS 15の新機能ですCanvasTimelineView、マテリアル、フォアグラウンド スタイルなどの API を使用すると、開発者は宣言構文を使用して、高性能のカスタム グラフィックス、パーティクル アニメーション、没入型視覚効果を実装できます。

主な内容

グラフィックス アプリを作成する場合、開発者は矛盾に直面することがよくあります。つまり、フルスクリーンの没入型ビジュアル エクスペリエンスが必要ですが、コンテンツが衝撃音、ホーム インジケーター バー、またはキーボードによってブロックされるのではないかと心配しています。

以前のアプローチは、次を使用してさまざまなインセットを手動で計算することでした。GeometryReader安全領域を読み取ってレイアウトを調整します。コードは冗長であり、さまざまなデバイスでのパフォーマンスに一貫性がありません。

WWDC2021 の SwiftUI は、この問題点を解決するためにいくつかの重要な改善をもたらしました。

セーフエリアの微調整

ignoresSafeArea()修飾子は、どの安全領域を無視するかを指定できるようになりました。たとえば、背景画像を画面全体に表示したいが、コンテンツはキーボードを避ける必要があるとします。

ContentView()
    .ignoresSafeArea(.keyboard)

03:52

さらに強力なのが、safeAreaInset修飾子。これにより、メイン コンテンツの安全領域を自動的に縮小してブロックされないようにしながら、補助コンテンツ (下部ツールバーなど) を特定の端に追加できます。

List {
    // メインコンテンツ
}
.safeAreaInset(edge: .bottom) {
    // 下部ツールバー
    HStack {
        Button("Cancel") {}
        Spacer()
        Button("Save") {}
    }
    .padding()
    .background(.thinMaterial)
}

09:03

素材と鮮やかさ

iOS 15 では、マテリアル ブラー エフェクトが導入されています。ultraThin到着ultraThickレベルは全部で6つあります。協力する.foregroundStyle(.secondary)階層スタイルを使用すると、テキストに自動的に鮮やかな効果が適用され、背景色に応じてコントラストが動的に調整されます。

Text("Hello")
    .foregroundStyle(.secondary)
    .background(.ultraThinMaterial)

06:13

Canvas と TimelineView

多数のグラフィック要素 (パーティクル システム、データ ビジュアライゼーションなど) を描画する必要があるシーンの場合、Canvas直接描画が可能となり、組み合わせをはるかに超えるパフォーマンスを発揮します。View

TimelineViewアニメーションの更新を制御可能にするには、次のように使用できます.animationスケジュールは、CADisplayLink と同様のフレームごとのコールバックを取得します。

##詳細

前景スタイルの新しいシステム

foregroundStyle古いものを置き換えたforegroundColor、より豊富なセマンティック レベルをサポートします。

VStack {
    Text("Primary")
        .foregroundStyle(.primary)
    Text("Secondary")
        .foregroundStyle(.secondary)
    Text("Tertiary")
        .foregroundStyle(.tertiary)
    Text("Quaternary")
        .foregroundStyle(.quaternary)
}
.foregroundStyle(.purple)

07:08

キーポイント:

  • .primary到着.quaternaryこれはセマンティック レベルであり、マテリアル コンテキストで Vibrancy エフェクトを自動的に取得します。
  • 外層.foregroundStyle(.purple)すべてのサブビューの前景色を紫に統一します
  • 通り抜けもできますLinearGradientおよびその他の複雑なスタイル
let blueGradient = LinearGradient(
    colors: [.blue, .teal],
    startPoint: .leading,
    endPoint: .trailing
)

VStack {
    Text("Primary").foregroundStyle(.primary)
    Text("Secondary").foregroundStyle(.secondary)
}
.foregroundStyle(blueGradient)

07:41

キャンバス描画の基本

Canvas特殊な描画ビューであり、ピクセルの直接制御が必要なシーンに適しています。

Canvas { context, size in
    // 画像を解決する(描画のたびに再解決しない)
    let resolvedImage = context.resolve(Image("sparkle"))

    // 画像サイズを取得する
    let imageSize = resolvedImage.size

    // 中央に描画する
    let rect = CGRect(
        x: size.width / 2 - imageSize.width / 2,
        y: size.height / 2 - imageSize.height / 2,
        width: imageSize.width,
        height: imageSize.height
    )

    context.draw(resolvedImage, in: rect)
}

13:12

キーポイント:

  • context.resolve()パフォーマンスを向上させるために画像リソースを事前に解析する
  • クロージャはありません。ViewBuilder、通常の for ループを使用できます
  • すべての描画は順番に実行され、後で描画されたものは先に描画されたものを上書きします。

TimelineView を使用してアニメーションを作成する

TimelineView(.animation) { timeline in
    Canvas { context, size in
        let time = timeline.date.timeIntervalSinceReferenceDate
        let angle = Angle(radians: time.remainder(dividingBy: 3) * 2 * .pi / 3 * 2)
        let offsetX = cos(angle.radians) * 50

        let resolvedImage = context.resolve(Image("sparkle"))
        let imageSize = resolvedImage.size

        for i in 0..<particleCount {
            var contextCopy = context
            contextCopy.opacity = 0.7
            contextCopy.blendMode = .screen

            let rect = CGRect(
                x: size.width / 2 + offsetX - imageSize.width / 2,
                y: size.height / 2 + CGFloat(i) * 10 - imageSize.height / 2,
                width: imageSize.width,
                height: imageSize.height
            )
            contextCopy.draw(resolvedImage, in: rect)
        }
    }
}
.gesture(
    TapGesture()
        .onEnded { _ in
            particleCount += 1
        }
)

18:38

キーポイント:

  • TimelineView(.animation)画面のリフレッシュ レートで更新をトリガーする
  • context値型です。コピー後に変更しても、元のコンテキストには影響しません。
  • .blendMode(.screen)重なった部分を明るくし、発光効果に適しています。
  • ジェスチャは Canvas の外層に追加できますが、内部の個々の要素にジェスチャを追加することはできません。

アクセシビリティのサポート

Canvas は単一のビットマップであり、内部要素はアクセシビリティには表示されません。説明を手動で追加する必要があります:

Canvas { context, size in
    // 描画コード
}
.accessibilityLabel("Particle animation showing \(particleCount) sparkles")
.accessibilityAddTraits(.isImage)

21:22

重要ポイント

1.写真/ビデオ編集アプリにリアルタイム フィルター プレビューを追加

Canvas を使用してフィルタリングされたイメージを描画し、TimelineView を使用して 60fps のリアルタイム プレビューを実現します。入口 API: Canvas + context.draw() + context.filter

2.カスタム チャートとデータの視覚化を構築

数百のデータ ポイントをプロットする必要があるシナリオでは、結合した Shape よりも Canvas の方が優れたパフォーマンスを発揮します。TimelineView と組み合わせて、動的なデータフロー表示を行えます。入口 API: Canvas + context.fill(path, with: .color(...))

3.ゲーミフィケーションされたパーティクルエフェクトを実装します

花火、雪の結晶、スターライトなどのエフェクトは、Canvas + blendMode(.screen) で簡単に実装できます。パーティクルの状態を ObservableObject にカプセル化すると、TimelineView が更新を駆動します。入口 API: TimelineView(.animation) + @StateObject

4.没入型の読み取り/作成インターフェイスを設計します

ignoresSafeArea(.keyboard) を使用して背景画像を全画面に拡張し、safeAreaInset でフローティング ツールバーを配置し、すりガラスの背景としてマテリアルを使用します。入口 API: .background(Image(...).ignoresSafeArea()) + .safeAreaInset

5. Vibrancy サイドバーを macOS アプリに追加

SwiftUI のマテリアルは、macOS 上のネイティブの Vibrancy エフェクトに自動的に適応します。.listStyle(.sidebar).foregroundStyle(.secondary) を組み合わせることで、システムレベルのビジュアル品質を得られます。入口 API: .background(.ultraThinMaterial)

関連セッション

コメント

GitHub Issues · utterances