WWDC Quick Look 💓 By SwiftGGTeam
What's new in visionOS 26

What's new in visionOS 26

元の動画を見る

ハイライト

visionOS 26 は volume を第一級市民に格上げしました:sheet を表示でき、境界をはみ出させられ、3D オブジェクトがジェスチャーに追随して回転し、それらはすべてたった一つの view modifier で実現可能です。


主要内容

昨年 Vision Pro が発売されて以来、開発者が最も頻繁に遭遇した落とし穴は、「volume が『閉じた箱』のように振る舞う」というものでした。コンテナ内の 3D コンテンツはレンダリングできますが、alert、sheet、menu といった日常的な UI コンポーネントは volume 内で使用できず、ウィンドウ境界を超えるジオメトリは裁ち切られてしまいます。また、3D オブジェクトの回転ジェスチャーを一から実装する必要がありました。その結果、すべての volumetric アプリが車輪の再発明を繰り返し、体験もまちまちという状態でした。

visionOS 26 はこれらの痛点を一つずつ解消しました。Edwin は冒頭で基本方針を明確にしました。SwiftUI の既存の 2D レイアウトツールを自然に 3D へと拡張するというアプローチです。depthAlignmentVStack を前後軸に沿って整列させ、rotation3DLayout は回転をレイアウトシステムに組み込み、preferredWindowClippingMargins はコンテンツの境界はみ出しを許可し、Object Manipulation API は一つの .manipulable() 修飾子でカスタムジェスチャースタックを置き換えます。システムはさらに、SwiftUI、RealityKit、ARKit の三つの座標系を統合し、RealityKit を書く開発者は RealityView 経由で中継する必要がなくなりました。entity に SwiftUI ジェスチャーと attachment を直接取り付けられるようになりました。これらの変更が合わさり、volume はついに完全なアプリのメインシーンを担えるようになりました。

詳細

SwiftUI レイアウトが三次元へ(02:25

// Layout types back align views by default

struct LandmarkProfile: View {

    var body: some View {
       VStackLayout().depthAlignment(.front) {
            ResizableLandmarkModel()
            LandmarkNameCard()
        }
    }
}

要点:

  • VStackLayout() はおなじみの垂直スタックで、以前は X/Y 平面でのみ機能していました。
  • .depthAlignment(.front) はすべてのサブビューを Z 軸に沿って同一の前面に整列させます。3D モデルは奥に配置でき、名刺は自動的にモデルの最前面に貼り付くため、可読性が大幅に向上します。
  • これはレイアウトレベルの修飾子であり、手動で offset を計算する必要がありません。

Volume 内のコンテンツはみ出し(04:22

// Dynamic Bounds Restrictions

struct ContentView: View, Animatable {

    var body: some View {
        VStackLayout().depthAlignment(.front) {
            // . . .
        }
        .preferredWindowClippingMargins(.all, 400)
    }
}

要点:

  • preferredWindowClippingMargins(.all, 400) はシステムに対して、コンテンツが四方それぞれ 400 ポイントまではみ出すことを許可するよう指示します。
  • 用途は、仮想オブジェクトをウィンドウから「突き出させる」ことです。例えば、山が volume から顔を出したり、滝が境界を越えたりする場合に、volume のサイズを大きくする必要がありません。
  • これは「設定(preferred)」であり、システムは必要に応じて距離と遮蔽状況に基づいて自動的に裁ち切りを行います。

Object Manipulation:一つの modifier で完結(05:05

// Apply the manipulable view modifier to each Model3D block per 3D object

struct RockView: View {
    var body: some View {
        RockLayout {
            ForEach(rocks) { rock in
                Model3D(named: rock.name, bundle: realityKitContentBundle) {
                    model in
                    model.model?
                        .resizable()
                        .scaledToFit3D()
                }
                .manipulable()
            }
        }
    }
}

要点:

  • .manipulable()Model3D が両手によるグラブ、回転、スケーリングを自動的にサポートし、現実の物体と一致する物理的直感性を提供します。
  • DragGesture + RotateGesture3D の組み合わせを記述する必要はなく、両手の協調処理も手動で行う必要がありません。
  • RealityKit を使用する開発者は ManipulationComponent.configureEntity(rock) を呼ぶだけで同じ動作を得られます。Quick Look でプレビューする USDZ モデルは、この機能を無料で利用できます。

SwiftUI ジェスチャーを Entity に直接割り当て(06:36

// Gestures on entities
struct GestureExample: View {
    @GestureState private var dragMountain: Float = 0
    @GestureState private var dragTerrain: Float = 0
		var body: some View {
        RealityView { content in
            let drag1 = GestureComponent(
                DragGesture().updating($dragMountain) { value, offset, _ in
                    offset = Float(value.translation.width)
                })
            let drag2 = GestureComponent(
                DragGesture().updating($dragTerrain) {evalue, offset, _ in
                    offset = Float(value.translation.width)
                })
            mountain.components.set(drag1)
            terrain.components.set(drag2)
        } update: { content in
            // . . .
        }
    }
}

要点:

  • GestureComponent は SwiftUI の DragGesture を直接 entity に取り付け、RealityView 経由でのヒットテストの中継が不要になります。
  • 各 entity は独立したジェスチャーを持つことができ、相互に干渉しません。以前は targetedToEntity の分岐判定を長々と記述する必要がありました。
  • @GestureState は引き続き SwiftUI の状態管理を使用し、従来の記述方法をそのまま移行できます。

Look to Scroll:視線だけでスクロール(33:45

// SwiftUI
var body: some View {
    ScrollView {
        HikeDetails()
    }
    .scrollInputBehavior(.enabled, for: .look)
}


// UIKit
let scrollView: UIScrollView = {
    let scroll = UIScrollView()
    scroll.lookToScrollAxes = .vertical
    return scroll
}()

要点:

  • SwiftUI では一行 scrollInputBehavior(.enabled, for: .look) を追加するだけで、ユーザーの視線が端に移動するとスクロールがトリガーされ、手を空ける必要がありません。
  • UIKit ルートでは lookToScrollAxes を使用し、必要に応じて垂直、水平、またはその両方を指定します。
  • 閲覧型、長コンテンツブラウジング型アプリが最初の受益者です。ゲームでは注意が必要で、瞄准操作との競合を避ける必要があります。

その他の重要なアップデート

  • Foundation Models フレームワーク(10:53):オンデバイス LLM へのアクセス、guided generation と tool calling をサポート。
  • Spatial Audio Experience API(08:26):各 window/volume が独自の空間オーディオソースを持ち、シーン間でシームレスに移動可能。
  • Environment Occlusion(09:04):EnvironmentBlendingComponent を通じて、仮想オブジェクトが現実の静止物体によって遮蔽されるように。
  • Nearby Window Sharing と共有 ARKit world anchors:同じ部屋の複数人が同一の volume を操作可能。既存の SharePlay コードは変更なしで nearby エクスペリエンスを獲得でき、isNearbyWithParticipant チェックを追加するとより詳細な差別化が可能。
  • Spatial Browsing と HTML <model> :ウェブページに直接 USDZ モデルを配置し、長文の閲覧時に空間リーディングモードに入る。
  • 企業 API:Protected Content は一つの modifier でスクリーンショット/録画/AirPlay を禁止。Window Follow Mode はウィンドウがユーザーの移動に追随。Return to Service はデバイス共有時の安全なリセットに使用。

重要ポイント

  • volume をメインステージに、window を付属物に:以前は window をメインに、volume に 3D アクセサリーを格納していましたが、visionOS 26 以降は逆の方が合理的です。volume は sheet を表示でき、境界をはみ出し、空間オーディオを扱えるようになり、メインのインタラクションを完全に内包できます。

    • なぜ価値があるか:アプリが最初から空間感を備え、ユーザーが二次元ウィンドウで Vision Pro の違いを感じられない状態を回避できます。
    • 始め方:最初のシーンを WindowGroup(.volumetric) に変更し、depthAlignment(.front) で主要要素をレイアウトし、preferredWindowClippingMargins で重要なオブジェクトを境界から突き出させます。
  • 自作の 3D ジェスチャースタックは削除し、すべて .manipulable() / ManipulationComponent に置き換え:ジェスチャーの協調、両手スケーリング、慣性バウンスといった詳細は Apple が統一済みです。自力で実装してもシステムレベルの一貫性を達成するのは困難です。

    • なぜ価値があるか:ユーザーは Quick Look、システムフォト、他のサードパーティアプリですでに一貫した筋肉記憶を形成しており、カスタムジェスチャーはこのメンタルモデルを破壊します。
    • 始め方:既存の DragGesture3D + RotateGesture3D の組み合わせを置き換えます。RealityKit 側では RealityView の make 段階で各インタラクティブな entity に対して一度 ManipulationComponent.configureEntity(_:) を呼び出します。
  • メディア系アプリは APMP(Apple Projected Media Profile)を優先的にサポート:Canon、GoPro、Insta360 で撮影された 180/360 度と広角素材が統一メタデータを持ち、インポート後はシステムの没入型再生パイプラインを直接通せます。

    • なぜ価値があるか:ユーザーは外部カメラから素材をインポートする機会が増えており、APMP により各レンズ仕様ごとに特別処理をする必要がなくなります。
    • 始め方:アップロードチェーンが元のメタデータを保持しているか確認。プレイヤー側はシステム提供の没入型 player を使用し、projection 情報でレンダリングを駆動します。
  • 企業内アプリはデフォルトで Protected Content を適用:金融、医療、デザイン稿レビューといったビューでは、スクリーンショットと AirPlay はコンプライアンス上の高リスクポイントです。

    • なぜ価値があるか:一つの view modifier で一種のコンプライアンス問題を解決でき、ビジネスロジックの変更が不要です。
    • 始め方:機密データを表示する view のルートノードを探し、Protected Content modifier を追加。外部共有ユースケースでは Window Follow Mode でさらに制限が必要か評価します。

関連セッション

コメント

GitHub Issues · utterances