What's new in watchOS design
Design 入门 22m

watchOS 设计新趋势

What's new in watchOS design

2020年6月23日

在 Apple 官方观看视频

一句话判断

watchOS 7 的设计更新不是表面功夫——新的全屏体验、改进的导航模式和 Complication 的新能力,都在重新定义”手腕上的应用应该长什么样”。

这场 Session 讲了什么

watchOS 7 带来了一系列设计层面的变化,Session 从设计原则出发,逐一介绍了新特性和最佳实践。最显著的变化是应用导航模式的演进——Apple 推出了更清晰的全屏体验和列表导航模式,替代了之前有些混乱的分页导航。

Complication(表盘复杂功能)获得了重大升级。watchOS 7 引入了新的 Complication 家族,支持展示更多类型的信息,包括圆形、矩形和额外的图形样式。更重要的是,一个应用现在可以提供多个 Complication,用户可以在同一个表盘上展示同一应用的不同信息维度。

Session 还讨论了 watchOS 应用的视觉设计原则:大字体、高对比度、触觉反馈优先。Apple 强调手表上的每一次交互都应该在 2-3 秒内完成——如果用户需要盯着屏幕超过 5 秒,说明你的设计出了问题。新的计时器、闹钟和地图等系统应用都是这些原则的范例。

值得深挖的点

多 Complication 策略

以前每个应用只能提供一个 Complication。watchOS 7 允许一个应用提供多个 Complication 家族成员,比如天气应用可以同时提供”当前温度”和”未来降雨概率”两个 Complication。这改变了应用与表盘的交互模式——用户可以在同一个 Infograph 表盘上同时看到温度和降雨概率,不需要切换表盘或打开应用。

从分页导航到列表导航

很多 watchOS 应用采用了分页(paging)导航——水平滑动切换页面。Apple 在 watchOS 7 中更推荐列表导航模式,特别是在信息层级超过两层时。列表导航的垂直滚动更符合手表的单手操作习惯,也更容易通过 Digital Crown 精确控制。Session 建议只在内容确实平行且不超过 3 个时才用分页模式。

代码片段

// watchOS 7 多 Complication 支持
import ClockKit

class ComplicationController: NSObject, CLKComplicationDataSource {
    
    // 声明支持的 Complication 族
    func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
        let descriptors = [
            // 当前温度 Complication
            CLKComplicationDescriptor(
                identifier: "current_temp",
                displayName: "当前温度",
                supportedFamilies: CLKComplicationFamily.allCases
            ),
            // 降雨概率 Complication
            CLKComplicationDescriptor(
                identifier: "rain_chance",
                displayName: "降雨概率",
                supportedFamilies: CLKComplicationFamily.allCases
            ),
            // AQI 空气质量 Complication
            CLKComplicationDescriptor(
                identifier: "aqi",
                displayName: "空气质量",
                supportedFamilies: [.graphicCorner, .graphicCircular]
            ),
        ]
        handler(descriptors)
    }
    
    func getCurrentTimelineEntry(
        for complication: CLKComplication,
        withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void
    ) {
        // 根据 complication.identifier 返回对应数据
        switch complication.identifier {
        case "current_temp":
            let entry = createTemperatureEntry(for: complication)
            handler(entry)
        case "rain_chance":
            let entry = createRainEntry(for: complication)
            handler(entry)
        default:
            handler(nil)
        }
    }
}
// watchOS 列表导航模式
import SwiftUI

struct WorkoutListView: View {
    let workouts: [WorkoutType] = [
        .running, .cycling, .swimming, .yoga, .hiking
    ]
    
    var body: some View {
        // 使用 List 进行垂直滚动导航
        List(workouts) { workout in
            NavigationLink(destination: WorkoutDetailView(workout: workout)) {
                HStack {
                    Image(systemName: workout.icon)
                        .foregroundColor(workout.color)
                    Text(workout.name)
                        .font(.body)
                }
            }
            .listRowBackground(Color.clear)
        }
        .listStyle(.carousel)  // watchOS 特有的 carousel 样式
        .navigationTitle("训练")
    }
}

struct WorkoutDetailView: View {
    let workout: WorkoutType
    
    var body: some View {
        VStack(alignment: .leading) {
            Text(workout.name)
                .font(.title3)
                .fontWeight(.semibold)
            
            Text(workout.description)
                .font(.caption)
                .foregroundColor(.secondary)
            
            Button("开始") {
                // 启动训练
            }
            .buttonStyle(.borderedProminent)
        }
    }
}
// SwiftUI 全屏 watchOS 体验
import SwiftUI

struct MetricsView: View {
    @State private var heartRate: Double = 72
    @State private var distance: Double = 0
    
    var body: some View {
        // 全屏沉浸式数据展示
        ZStack {
            Color.black.ignoresSafeArea()
            
            VStack(spacing: 8) {
                // 大字体显示核心数据
                Text("\(Int(heartRate))")
                    .font(.system(size: 48, weight: .bold, design: .rounded))
                    .foregroundColor(.red)
                    .monospacedDigit()
                
                Text("BPM")
                    .font(.caption2)
                    .foregroundColor(.secondary)
                
                // 次要信息
                HStack {
                    Label("\(String(format: "%.1f", distance))", 
                          systemImage: "figure.walk")
                    Text("km")
                }
                .font(.caption)
                .foregroundColor(.green)
            }
        }
    }
}

最佳实践

  • 每个手表界面只展示一个核心信息,次要信息用小字体或图标补充
  • 使用 Digital Crown 作为主要交互输入——它是手表上最精确的输入方式
  • Complication 的数据更新要高效,使用 CLKComplicationTimelineEntry 的批量时间线条目减少更新频率
  • 深色背景 + 高对比度文字是手表界面的黄金法则,避免浅色背景
  • 测试时一定要在真表上操作,模拟器上的交互体验和真实手腕操作差别很大

还有什么值得关注

  • watchOS 7 支持多表盘共享——用户可以将自定义的表盘配置分享给朋友,Complication 会自动适配
  • 新的 tinted 表盘模式允许用户自定义 Complication 的强调色,你的 Complication 需要适配不同的配色方案
  • Session 强调了手腕抬起的”瞥一眼”场景——用户从抬腕到看到信息应该在 1 秒内完成
WWDC 2020