WWDC Quick Look 💓 By SwiftGGTeam
Meet watchOS 10

Meet watchOS 10

元の動画を見る

ハイライト

watchOS 10 は Apple Watch の UI を根本から再設計しました。Dial、Infographic、List の 3 つの基本レイアウトを導入し、水平ページングを垂直ページングに置き換え、ソースリストで階層ナビゲーションを簡素化し、半透明のマテリアルと意味的な背景ですべての画面を読みやすくしました。


主要内容

小さな画面で App が使いにくい理由

2014 年の Apple Watch 登場から 2023 年まで、ハードウェアは数世代進化しました。画面は大きく明るくなり、常時表示、セルラー、より多くのセンサーが加わりました。App のデザインパターンはそれに追いついていませんでした。

3 つの課題が残り続けていました。

第一に、ナビゲーションが統一されていませんでした。水平ページング(左右スワイプ)を使う App、階層的な push/pop を使う App、両方を混ぜる App がありました。システム App で学んだ操作が、サードパーティ App では通用しません。

第二に、レイアウトがバラバラでした。ボタンの位置、ラベルのサイズ、コンテンツ領域の境界は App ごとに独自設計でした。並べて見ると視覚的にまとまりがありません。

第三に、情報密度のコントロールが難しかったのです。小さな画面に文字を詰めすぎると読めず、少なすぎるとスペースを無駄にします。「1 画面にどれだけ載せるか」を決めるシステムルールがありませんでした。

watchOS 10 のデザインシステム再構築

watchOS 10 はデザインシステムを全面的に作り直しました。中核となる考え方は、各 App の好みではなく、ディスプレイの物理的形状からレイアウトルールを定義することです。

Apple は 3 つの基本レイアウトを定義しました(01:40)。

  • Dial(ダイアルレイアウト): タイマーやストップウォッチのように、1 つの重要な数値向け。情報は中央に、周囲に余白。
  • Infographic(インフォグラフィックレイアウト): Activity リングや天気詳細のように、文脈付きの複雑なデータ向け。大きな領域にメインコンテンツ、上下に補足情報。
  • List(リストレイアウト): メール、連絡先、設定のように、同種の複数項目向け。

これらのレイアウトは watchOS 10 がサポートするすべての Apple Watch サイズに自動適応します。デザイナーがピクセルを計算する必要はなく、コントロールのサイズ・位置・間隔はシステムが決めます。

ナビゲーションも統一されました。Digital Crown が中核を担います。回転で垂直ページ間を移動し、リストをスクロールし、データを確認します。サイドボタン単押しでコントロールセンター、ダブルクリックで Wallet。ホーム画面は縦スクロールし、Digital Crown を回して下方向に閲覧します。

マテリアルと背景が情報を伝える

watchOS 10 では新しいマテリアル(Materials)システムが導入されました。レイヤーごとに異なる透明度の半透明効果で視覚的階層を作ります(05:03)。

コンテンツはステータスバーの下までスクロールでき、ステータスバーは半透明マテリアルで読みやすさを保ちます。かつて空いていた領域が有効活用されます。意味的なシステムカラーを使う要素は、背景マテリアルに応じてコントラストが自動調整されます。

背景は装飾だけではありません。World Clock の背景は現在のタイムゾーンの日照、Weather は天候、Stocks は騰落を色で示します。Activity では各インフォグラフィックページの背景色がリング色に合わせられます — Move は赤、Exercise は緑、Stand は青(04:28)。


詳細

垂直ページング: Digital Crown 駆動のページ切り替え

垂直ページングは watchOS 10 の中核的なナビゲーション革新です(02:49)。

以前の watchOS App は水平ページング(左右スワイプ)が多く、2 つの問題がありました。小さな画面で指が触れると誤操作しやすく、スワイプ自体がコンテンツを隠します。

垂直ページングでは Digital Crown の回転でページを切り替えます。Activity では、Crown を回すと Activity リング概要から Move 詳細、Exercise 詳細、Stand 詳細へ移ります。ページインジケータは Digital Crown の位置に揃え、どんな背景でも見えます。

import SwiftUI

struct ActivityView: View {
    @State private var selection: ActivityTab = .overview

    enum ActivityTab: Hashable {
        case overview
        case moveDetail
        case exerciseDetail
        case standDetail
    }

    var body: some View {
        TabView(selection: $selection) {
            RingOverviewView()
                .tag(ActivityTab.overview)

            MoveDetailView()
                .tag(ActivityTab.moveDetail)

            ExerciseDetailView()
                .tag(ActivityTab.exerciseDetail)

            StandDetailView()
                .tag(ActivityTab.standDetail)
        }
        .tabViewStyle(.verticalPage)
    }
}

キーポイント:

  • TabView.tabViewStyle(.verticalPage) を付けると垂直ページングが有効になります
  • ユーザーは Digital Crown を回してページを切り替え、指でのスワイプは不要です
  • 各ページのコンテンツは 1 画面の高さに収めるべきで、ページごとに目的が明確になります
  • ページインジケータは Digital Crown の位置に自動で揃い、適応はシステムが処理します

垂直ページングを実装するときの 3 原則です。

原則 1: 各ページを 1 画面の高さに制限する。この制約により「このページで何を伝えるか」を考えざるを得ず、読みやすさが上がります。本当に超える必要があるなら、固定高さページの後に ScrollView を置きます。Messages は固定高さのピン留め会話ページの後に、通常の会話リストをスクロール表示しています。

原則 2: ページ間で共有する要素は複製せずアニメーションでつなぐ。Activity リングが概要と詳細の両方にあるなら、各ページに新インスタンスを置くのではなく、スケール・位置・情報密度の変化で表現します。この「オブジェクト恒存性」が視覚的な錨となり、同じものの別レイヤーを見ていると分かります。

原則 3: 水平ページングより垂直ページングを優先する。Digital Crown は縦方向に回るため、垂直ページングの方が自然です。

ソースリストナビゲーション: 多階層の代わりに 2 階層

ソースリスト(Source List)は、「複数のエンティティが同種の情報を共有する」場面向けの新しいナビゲーションです(03:36)。

World Clock を例にします。複数都市の現地時間が知りたい。ソースリストの設計: App を開くと選択中の都市の詳細が直接表示され、左上のボタンで都市リストを開き、別の都市を選ぶと詳細に戻ります。

従来の階層ナビゲーションは「リスト → タップ → 詳細 → 戻る → リスト」。ソースリストは「詳細(デフォルト) → ボタン → 都市切り替え → 新しい詳細」。ユーザーはほとんど詳細を見ており、都市の切り替えは軽い操作です。

import SwiftUI

struct WorldClockView: View {
    @State private var cities: [City] = [
        City(name: "San Francisco", timeZone: "PST"),
        City(name: "New York", timeZone: "EST"),
        City(name: "London", timeZone: "GMT"),
    ]
    @State private var selectedCity: City?

    var body: some View {
        NavigationSplitView {
            List(cities, selection: $selectedCity) { city in
                CityRow(city: city)
            }
        } detail: {
            if let city = selectedCity {
                CityDetailView(city: city)
            } else {
                ContentUnavailableView("Select a City", systemImage: "globe")
            }
        }
    }
}

キーポイント:

  • NavigationSplitView は watchOS 10 の新コンテナで、ソースリストナビゲーションを自動提供します
  • サイドバーがエンティティリスト、detail が選択エンティティの詳細です
  • ナビゲーションアニメーションと戻る動作はシステムが処理します
  • ナビゲーションスタックを手動管理する必要はありません

従来の階層ナビゲーションも watchOS 10 に残っていますが、ソースリストや垂直ページングで表現できない場合だけ使うことを Apple は推奨しています。Settings や Mail は構造が自然に多階層な例です。watchOS 10 では階層ナビゲーション用の新しい遷移アニメーションも追加され、どの階層に入ったかが分かりやすくなっています。

背景コンテンツ: 色が情報を伝える

watchOS 10 では背景コンテンツが情報を伝えます。純粋な装飾ではありません(04:28)。

import SwiftUI

struct ActivityDetailView: View {
    var type: ActivityType

    var body: some View {
        ZStack {
            // 背景色を Activity タイプに合わせ、位置を感知しやすくする
            type.backgroundColor
                .ignoresSafeArea()

            VStack(spacing: 12) {
                Text(type.title)
                    .font(.title3)
                    .foregroundStyle(.primary)

                Text("\(type.progress, format: .percent)")
                    .font(.system(size: 48, weight: .bold))
                    .foregroundStyle(.primary)
            }
        }
    }
}

enum ActivityType {
    case move, exercise, stand

    var backgroundColor: Color {
        switch self {
        case .move: return .red.opacity(0.15)
        case .exercise: return .green.opacity(0.15)
        case .stand: return .blue.opacity(0.15)
        }
    }

    var title: String {
        switch self {
        case .move: return "Move"
        case .exercise: return "Exercise"
        case .stand: return "Stand"
        }
    }

    var progress: Double {
        switch self {
        case .move: return 0.75
        case .exercise: return 0.5
        case .stand: return 0.83
        }
    }
}

キーポイント:

  • 背景色は見た目だけではありません — Move / Exercise / Stand で色を分け、一目でどのページか分かります
  • opacity(0.15) で背景を十分に薄くし、前景テキストの可読性を保ちます
  • 前景テキストは .primary の意味色を使い、コントラストはシステムが調整します
  • 背景は色・グラデーション・アニメーションなど自由ですが、追加情報を提供する必要があります

マテリアル: 画面上部のスペースを取り戻す

watchOS 10 のマテリアルシステムは半透明効果で階層を区別します(05:03)。

ステータスバー下のコンテンツは画面最上部まで伸ばせ、ステータスバーは半透明オーバーレイで読みやすさを保ちます。

import SwiftUI

struct WeatherDetailView: View {
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    // ステータスバーを避ける必要なく、画面上部から開始
                    CurrentConditionsView(temperature: 72, condition: "Sunny")
                    HourlyForecastView()
                    TenDayForecastView()
                }
            }
            .toolbarBackground(.ultraThinMaterial, for: .navigationBar)
            .navigationTitle("San Francisco")
        }
    }
}

キーポイント:

  • .toolbarBackground(.ultraThinMaterial, for: .navigationBar) でナビゲーションバーに半透明マテリアルを適用
  • スクロール中、コンテンツは半透明領域の下を通過し、利用可能スペースを最大化
  • ステータスバーの文字は常に読みやすく、色はシステムが調整
  • ステータスバー用の padding を手動で確保する必要はありません

Digital Crown をデータ確認ツールとして使う

リストナビゲーションやページ切り替え以外では、Digital Crown をデータ確認ツールとして使えます(03:36)。

World Clock が良い例です。詳細ページで選択都市の時刻を見ながら、Crown を回して時間を前後にずらせます。「夜 8 時にロンドンの同僚に電話したら、向こうは何時か」を確認するのに便利です。

import SwiftUI

struct WorldClockDetailView: View {
    @State private var timeOffset: TimeInterval = 0

    var body: some View {
        VStack {
            Text(adjustedTime, style: .time)
                .font(.system(size: 56, weight: .medium))
                .focusable()
                .digitalCrownRotation(
                    $timeOffset,
                    from: -12 * 3600,
                    through: 12 * 3600,
                    by: 300,
                    sensitivity: .low,
                    isContinuous: true
                )

            Text("Current: \(Date.now, style: .time)")
                .font(.caption)
                .foregroundStyle(.secondary)
        }
    }

    var adjustedTime: Date {
        Date.now.addingTimeInterval(timeOffset)
    }
}

キーポイント:

  • .digitalCrownRotation で Crown の回転を TimeInterval 値にバインド
  • from:through: でオフセット範囲(-12〜+12 時間)を定義
  • by: 300 でステップを 5 分に設定
  • sensitivity: .low で細かい調整向けに感度を下げる
  • isContinuous: true で境界到達後も値を循環させられる

重要ポイント

  1. 垂直ページングで App の情報アーキテクチャを再設計する: 水平ページングや深い多階層ナビゲーションを使っているなら、垂直ページングへ。各ページに 1 つの核心情報を置き、Digital Crown で切り替える。価値: 垂直ページングは watchOS 10 のネイティブナビゲーションで、システム App はすべて採用。新しい操作を覚える必要がない。始め方: 水平スワイプを TabView + .tabViewStyle(.verticalPage) に置き換え、各ページを 1 画面の高さに収める。

  2. 機能領域ごとに意味的な背景を導入する: 天気 App なら天候に、フィットネス App なら運動タイプに応じて背景色を変える。価値: システム App はすでに意味的な背景を使っており、ユーザーはそれを期待している。色は即座の視覚的手がかりとなり、状態認識の時間を短縮する。始め方: SwiftUI で ZStack に背景レイヤーを置き、データ状態で色やグラデーションを切り替え、不透明度は 0.1〜0.2 程度に。

  3. 深いナビゲーションをソースリストに置き換える: 複数の同種エンティティ(アカウント、デバイス、プロジェクト)を管理する App なら、ソースリストを使う。デフォルトエンティティの詳細を直接表示し、左上に切り替えボタン。価値: ナビゲーション階層が 1 段減る。ユーザーはほとんど詳細を見て、エンティティ切り替えはたまに行う。始め方: NavigationSplitView でサイドバーにエンティティリスト、右に詳細。

  4. マテリアルでコンテンツ領域を最大化する: ステータスバー用に確保していた空白を活用し、コンテンツを画面上部まで伸ばす。価値: Apple Watch の 1 ピクセルも無駄にできない。マテリアルでかつて使われなかった領域を取り戻せる。始め方: ScrollView.toolbarBackground(.ultraThinMaterial, for: .navigationBar) を組み合わせる。

  5. オブジェクト恒存アニメーションでページをつなぐ: 同じデータ要素が複数の垂直ページに現れるなら、スケールと位置の遷移でつなぎ、2 つのインスタンスを置かない。価値: 視覚的な錨となり、同じものの別レイヤーを見ていると分かる。始め方: SwiftUI の matchedGeometryEffect でページ間の共有要素を遷移させる。


関連セッション

コメント

GitHub Issues · utterances