ハイライト
SwiftUI は、WWDC23 でクロスプラットフォーム機能の拡張を実現しました。新しいvisionOS シーン タイプ (WindowGroup、 Volume、ImmersiveSpace)、ObservableObject の代わりに @Observable マクロ、SwiftData ネイティブ統合、KeyframeAnimator および PhaseAnimator アニメーション API、および ScrollView のスクロール トランジションと位置合わせ機能です。
主な内容
SwiftUI が空間コンピューティングの時代に突入
以前は、3D インターフェイスを開発するには、まったく新しいフレームワークを学習する必要がありました。 visionOS のリリース後、このしきい値は破られました。
(01:55) SwiftUI は、visionOS で 3 つのシーン タイプをサポートします。WindowGroup2D ウィンドウとしてレンダリングされるこのコントロールには、深度に応じた 3D 効果が付いています。WindowGroupいつも通りお使いいただけますNavigationSplitView、TabViewなどの容器。
(02:26) はシーンを次のように宣言します.volumetricスタイルでは、ボリュームが得られます。 Volume は、ボード ゲームや建築モデルなどの 3D コンテンツを、限られたスペースに他のアプリケーションと並べて表示します。使用例Model3D静的モデルを表示するには、次を使用例します。RealityView照明とインタラクティブ性を備えた動的モデルを表示します。
(02:59)ImmersiveSpaceシーン タイプは没入型空間エクスペリエンスを定義し、混合とフルの 2 つの没入スタイルをサポートします。混合スタイルでは仮想コンテンツが現実の環境にオーバーレイされますが、フル スタイルではアプリケーションがユーザーの視野を完全に引き継ぐことができます。
watchOS 10 の新しいデザイン
(04:08) watchOS 10 はフルスクリーンのカラーデザインを特徴としています。NavigationSplitViewそしてNavigationStack新しいトランジションアニメーションを取得し、TabViewDigital Crown による垂直ページング スタイルを追加しました。
(04:53)containerBackgroundモディファイアは、プッシュおよびポップ時にアニメーション化されたトランジションを使用例して、ナビゲーションおよびタブ ビューの微妙な背景のグラデーションを構成します。containerBackgroundもサポートTabView。
ウィジェットがより多くのシーンに登場します
(05:54) ウィジェットは、iPadOS 17 のロック画面、iPhone のスタンバイ モード、macOS Sonoma のデスクトップなど、より多くの場所に表示されます。さらに重要なのは、ウィジェットが対話型コントロールをサポートするようになったということです。
(06:32)ToggleそしてButtonアプリ内コードはアプリ インテントを通じてトリガーでき、ウィジェットは SwiftUI のトランジションおよびアニメーション修飾子を使用例してアニメーション化できます。
データ フロー革命: @Observable と SwiftData
(10:44)@Observableマクロは、SwiftUI データ フローへの最大のアップグレードです。クラスに追加@Observable、マークする必要はありません@Published, SwiftUI は、読み取られたプロパティを自動的に追跡し、実際に使用例されるプロパティが変更された場合にのみビューを更新します。
(13:16) SwiftData は、新しいデータ モデリングおよび管理フレームワークです。バンドル@Observableと置き換えます@Modelマクロでは、モデルは Observable の利点をすべて保持しながら永続化機能を獲得します。使用例Queryプロパティ ラッパーはデータベースからデータを取得し、データが変更されるとビューが自動的に更新されます。
##詳細
###visionOS シーン タイプ
(01:55)visionOS 上WindowGroupiOS の場合と同じ方法:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
キーポイント:
WindowGroupvisionOS では 2D フラット ウィンドウとしてレンダリングされます。- ウィンドウ内のコントロールは、深度に応じた 3D 効果を自動的に取得します。
- などのコンテナ
NavigationSplitView、TabView直接使用例可能
音量を設定する必要がありますvolumetricスタイル:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.windowStyle(.volumetric)
}
}
キーポイント:
.windowStyle(.volumetric)ウィンドウを 3D ボリュームに変える- 使用例する
Model3D静的 USDZ モデルをロードする - 使用例する
RealityView照明、物理学、インタラクティブ性を備えたダイナミックな 3D シーンを作成する
ImmersiveSpace の宣言方法:
@main
struct MyApp: App {
var body: some Scene {
ImmersiveSpace(id: "space") {
ImmersiveView()
}
.immersionStyle(selection: .constant(.mixed), in: .mixed, .full)
}
}
キーポイント:
ImmersiveSpace独立したシーンタイプです -.immersionStyleサポートされているイマージョン モードを指定する- 混合モードでは、コンテンツを実際の環境に重ね合わせます。
- フルモードはユーザーの視野を完全に引き継ぎます
@監視可能なマクロ
(10:44) 以前に使用例されましたObservableObject各属性を追加する必要があります@Published:
class DogModel: ObservableObject {
@Published var dogs: [Dog] = []
@Published var isFavorite: Bool = false
}
ここで 1 行だけ:
@Observable class DogModel {
var dogs: [Dog] = []
var isFavorite: Bool = false
}
ビューで使用例する場合、プロパティ ラッパーは必要ありません。
struct DogCard: View {
let model: DogModel
var body: some View {
VStack {
Text(model.dogs.first?.name ?? "")
Toggle("Favorite", isOn: $model.isFavorite)
}
}
}
キーポイント:
@Observableマクロは監視可能な型に自動的に展開されます- 必要ありません
@Published、保存されているすべてのプロパティはデフォルトで監視可能です - ビューでプロパティを直接読み取る必要はありません
@ObservedObject- SwiftUI は実際に読み取られたプロパティのみを追跡し、未読のプロパティの変更は更新をトリガーしません。 - 中間ビューを渡すときに不必要な更新はトリガーされません
SwiftData の統合
(13:16) 置く@Observableと置き換えます@Model、モデルは永続化されます。
import SwiftData
@Model
class Dog {
var name: String
var breed: String
var spottedDate: Date
init(name: String, breed: String, spottedDate: Date = .now) {
self.name = name
self.breed = breed
self.spottedDate = spottedDate
}
}
アプリでモデル コンテナーをセットアップします。
@main
struct DogWatcherApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Dog.self)
}
}
ビュー内のデータをクエリします。
import SwiftData
struct DogList: View {
@Query(sort: \Dog.spottedDate, order: .reverse) private var dogs: [Dog]
var body: some View {
List(dogs) { dog in
Text(dog.name)
}
}
}
キーポイント:
@Modelマクロは、Observable 機能と永続化機能の両方を提供します -.modelContainer(for:)シーンレベルでストレージスタックをセットアップする -@Queryデータベースからデータを自動的に取得し、データが変更されたときにビューを更新します -sortパラメータは並べ替えルールを指定します- フィルタリングやページングなどの高度なクエリをサポート
キーフレーム アニメーター アニメーション
(19:07)KeyframeAnimator複数属性の並列アニメーションをサポートします。
struct LogoAnimation: View {
@State private var trigger = false
var body: some View {
KeyframeAnimator(
initialValue: AnimationValues(),
trigger: trigger
) { values in
Image("logo")
.offset(y: values.verticalTranslation)
.rotationEffect(values.rotation)
} keyframes: { _ in
KeyframeTrack(\.verticalTranslation) {
SpringKeyframe(30, duration: 0.25, spring: .smooth)
CubicKeyframe(-50, duration: 0.3)
SpringKeyframe(0, spring: .bouncy)
}
KeyframeTrack(\.rotation) {
LinearKeyframe(.degrees(0), duration: 0.25)
CubicKeyframe(.degrees(360), duration: 0.55)
}
}
}
}
struct AnimationValues {
var verticalTranslation: CGFloat = 0
var rotation: Angle = .zero
}
キーポイント:
initialValueすべてのアニメーション化可能なプロパティが含まれます -triggerEquatable 状態であり、変更時にアニメーションをトリガーします- 最初のクロージャは、アニメーション化された値を使用例してビューを構築します。
- 2 番目のクロージャは、時間の経過に伴う各属性の軌跡を定義します
-
KeyframeTrackサポートSpringKeyframe、CubicKeyframe、LinearKeyframe- 複数のトラックが並行して実行されます
フェーズアニメーターアニメーション
(20:29)PhaseAnimator一連のアニメーション ステージを順番に実行します。
struct WatchButton: View {
@State private var sightingCount = 0
var body: some View {
Button {
sightingCount += 1
} label: {
Image("dog-icon")
.phaseAnimator(
[AnimationPhase.idle, .rotate, .grow, .settle],
trigger: sightingCount
) { content, phase in
content
.rotationEffect(phase.rotation)
.scaleEffect(phase.scale)
} animation: { phase in
switch phase {
case .idle: .default
case .rotate: .spring(.snappy)
case .grow: .spring(duration: 0.3, bounce: 0.5)
case .settle: .spring(.bouncy)
}
}
}
}
}
enum AnimationPhase: CaseIterable {
case idle, rotate, grow, settle
var rotation: Angle {
switch self {
case .idle: .zero
case .rotate: .degrees(15)
case .grow, .settle: .zero
}
}
var scale: CGFloat {
switch self {
case .idle, .rotate: 1.0
case .grow: 1.3
case .settle: 1.0
}
}
}
キーポイント:
PhaseAnimatorステージを順番に実行し、前のステージが完了した後にのみ次のステージを開始します -trigger変更時にすべてのフェーズを最初から実行する- ステージごとに異なるアニメーションカーブを定義可能
- 新春アニメ対応
durationそしてbounceパラメータ -.snappy、.bouncy、.smoothデフォルトのスプリング構成です
ScrollView の改善
(27:53)scrollTransitionスクロール項目に視覚効果を追加します。
ScrollView {
LazyVStack {
ForEach(dogs) { dog in
DogCard(dog: dog)
.scrollTransition { content, phase in
content
.opacity(phase.isIdentity ? 1 : 0.5)
.scaleEffect(phase.isIdentity ? 1 : 0.8)
}
}
}
}
キーポイント:
scrollTransitionアイテムが表示領域に出入りするときに効果を適用する -phase含む.topLeading、.identity、.bottomTrailing3つの州- 必要ありません
GeometryReader
ページネーションと配置:
ScrollView(.horizontal) {
LazyHStack {
ForEach(parks) { park in
ParkCard(park: park)
.containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 16)
}
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
キーポイント:
containerRelativeFrameサブビューのサイズをコンテナに対して相対的にする -count画面をいくつかの部分に分割し、span占有するシェアの数を指定する -scrollTargetLayout調整する必要があるレイアウトにマークを付けます -scrollTargetBehavior(.viewAligned)スクロールが停止したときにビューの境界に揃える- もサポートしています
.paging行動
触覚フィードバック
(22:03) 新しいsensoryFeedback修飾子:
Button("Record Sighting") {
sightingCount += 1
}
.sensoryFeedback(.success, trigger: sightingCount)
キーポイント:
.success、.warning、.error事前定義されたフィードバック タイプを待つ -trigger変更時に触覚フィードバックを再生する- 触覚フィードバックを備えたすべてのプラットフォームをサポート
SFシンボルアニメーション効果
(24:55)symbolEffectモディファイアは SF シンボルにアニメーションを追加します。
Image(systemName: "slider.horizontal.3")
.symbolEffect(.bounce, options: .repeat(1))
キーポイント:
.pulse、.variableColor連続アニメーションです -.scale、.appear、.disappear、.replace状態変化アニメーションです -.bounceイベント告知アニメーションです- 単一のシンボルまたはビュー階層全体に適用可能
重要なポイント
-
visionOS 3D 表示アプリケーションを作成します
- 使用例する
WindowGroup+.volumetricスタイルショーケース製品3Dモデル - 使用例する
Model3DUSDZ ファイルをロードすると、ユーザーはジェスチャーを使用例して回転したり表示したりできます - 入口:
Model3D(named: "product")そして.windowStyle(.volumetric)
- 使用例する
-
既存のアプリケーションにインタラクティブなウィジェットを追加
- 既存の今日ウィジェットをインタラクティブ バージョンにアップグレードします。
- 使用例する
ToggleそしてButton+ アプリインテントにより、ユーザーはウィジェットを直接操作できるようになります - 入口:
#Preview(as: .systemSmall)プレビューウィジェット、AppIntentオペレーションを定義する
-
@Observable を使用例してデータ層を再構築します
- 既存のものを置く
ObservableObject+@Publishedモデルは次のように置き換えられます。@Observable- 大量の削除@ObservedObjectそして@EnvironmentObjectコード - 入口:置く
class Model: ObservableObjectに変更します@Observable class Model
- 既存のものを置く
-
アニメーションを使用例してオンボーディング プロセスを作成する
- 使用例する
PhaseAnimatorステップバイステップのアニメーションを作成する - 各ステップが切り替わるときに、さまざまなシンボルアニメーションとビュー遷移がトリガーされます
- 入口:
PhaseAnimator(phases, trigger: step)+symbolEffect
- 使用例する
-
ScrollView 主導のギャラリーを作成します
- 画像の横スクロール表示。各項目は画面幅の 80% を占めます
- 使用例する
scrollTransitionエッジアイテムを縮小して透明にする - 使用例する
scrollTargetBehavior(.viewAligned)カード吸着効果を実現 - 入口:
containerRelativeFrame(.horizontal, count: 5, span: 4)
関連セッション
- SwiftUI での観察を発見する — @Observable マクロがどのように動作するかについての深い理解
- SwiftData を使用例してアプリを構築する — SwiftData を使用例してアプリを最初から構築する
- SwiftUI で高度なアニメーションを使いこなす — KeyframeAnimator と PhaseAnimator の完全ガイド
- スクロール ビューを超えて — ScrollView のスクロール遷移、配置、カスタム動作
- 空間コンピューティングのための SwiftUI について —visionOS 上の SwiftUI の 3D 機能
コメント
GitHub Issues · utterances