WWDC Quick Look 💓 By SwiftGGTeam
Design for spatial input

Design for spatial input

观看原视频

Highlight

Apple 设计团队系统阐述了 visionOS 眼动和手势交互的核心原则:眼睛作为主要瞄准机制需要圆形元素、60pt 最小目标区域和动态缩放;手势交互优先使用间接捏合(手放膝盖上),直接触摸仅用于核心体验;眼动意图(Eye Intent)让简单交互获得魔法般的精确度。

核心内容

空间输入的五种模态

visionOS 支持多种输入方式:

  • 眼动 + 手势(最核心):看向按钮,轻捏手指选择,手可以放在膝盖上
  • 语音:搜索时无需打字,直接说话
  • 键盘 + 触控板:生产力场景的高效输入
  • 游戏控制器:游戏场景
  • 直接触摸:用手指触碰虚拟界面

Session 聚焦于眼动和手势这两个最核心的新输入方式。

眼动:主要瞄准机制

02:21)眼睛是空间体验的主要瞄准机制。系统所有界面都响应用户看向的位置。你可以毫不费力地瞄准任何元素,无论多远。

视野舒适度

03:06)尽管有无限画布,用户只能看到视野范围内的内容。视野中心最舒适,边缘容易疲劳。主内容放在视野中心,边缘用于次要操作(如工具栏)。

深度管理

04:00)人的眼睛一次只能聚焦一个距离。频繁切换焦点深度会导致眼疲劳。保持交互内容在同一深度,用 Z 轴微小变化表达层级。例如弹出模态视图时,主视图后退,模态保持在原距离。

目标区域

06:06)眼动瞄准的最小目标区域是 60 points。元素可以小于 60pt,通过间距补足。标准控件已内置合适的尺寸。

形状设计

05:18)使用圆形、胶囊形和圆角矩形。避免尖角形状——眼睛会聚焦在边缘而非中心。保持形状扁平,避免粗边框。文本和图标居中,使用充足的内边距。

动态缩放

07:13)系统窗口使用动态缩放——远离时变大,靠近时变小,保持目标区域大小不变。固定缩放会让远处界面变得难以瞄准。自定义 UI 也应使用动态缩放。

朝向

08:14)系统窗口始终面向用户。自定义窗口也应保持 UI 面向观看者,倾斜的界面难以阅读和操作。

Hover 效果

08:51)所有交互元素都需要 hover 效果——当用户看向元素时显示高亮反馈。效果要微妙,因为眼球移动很快。系统控件自动支持 hover,自定义元素需要手动添加。

隐私保护

09:40)眼动数据极其敏感。Hover 效果在 App 进程外渲染,App 只能知道哪个元素被聚焦,不知道眼睛的具体位置。只有在手势触发交互时,App 才收到聚焦信息。

眼动意图(Eye Intent)

10:04)长时间注视某个元素表示用户感兴趣。系统利用这一点展示额外信息:按钮 tooltip、Tab Bar 展开标签、搜索框的语音搜索触发。

辅助功能

11:04)Dwell Control 功能让用户只用眼睛就能选择内容——聚焦按钮一段时间后自动选中,无需手势。

手势交互

12:22)结合眼动瞄准,捏合手指是主要的确认方式。系统支持多种手势:

  • 轻捏:选择(相当于点击)
  • 捏合并拖拽:滚动
  • 双手手势:缩放、旋转

手势逻辑与 Multi-Touch 类似,用户无需学习。

眼动 + 手势的精确交互

14:29)缩放图片时,缩放原点由眼睛注视的位置决定——你看向哪里,哪里就被放大并居中。Markup 中画笔光标跟随手部移动,但看向画布另一侧并轻捏,光标会跳到你注视的位置。

直接触摸

15:52)伸手用手指直接触碰虚拟界面。适合近距离操作但容易疲劳。适用场景:

  • 需要近距离观察或操作物体的体验
  • 基于现实世界肌肉记忆的交互(如虚拟键盘)
  • 身体活动是体验核心的场景

补偿缺失的触觉反馈

16:51)虚拟键盘的按钮悬浮在基座上方,手指接近时显示 hover 状态和高亮,接触瞬间状态快速变化并伴随空间音效。这些视觉和听觉反馈补偿了缺失的触觉信息。

详细内容

自定义手势设计原则

13:17)当标准手势无法满足需求时,可以设计自定义手势。遵循以下原则:

  • 易于解释和执行,用户能快速学会
  • 与系统手势明显不同,避免冲突
  • 用户能持续重复而不疲劳
  • 误触发率低
  • 考虑辅助技术用户的兼容性
  • 手势含义在不同文化中不会引起误解
  • 提供 UI 回退方案

眼动友好的布局实践

import SwiftUI

struct EyeFriendlyLayout: View {
    var body: some View {
        VStack(spacing: 20) {
            // 主内容在视野中心
            MainContentView()
                .frame(maxWidth: 600)
            
            // 次要操作在底部
            HStack(spacing: 24) {
                SecondaryButton(icon: "gear", action: {})
                SecondaryButton(icon: "share", action: {})
            }
        }
        .padding(40)
    }
}

struct SecondaryButton: View {
    let icon: String
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            Image(systemName: icon)
                .font(.title2)
                .frame(width: 60, height: 60)
        }
        .buttonStyle(.borderless)
        // 圆形更容易瞄准
        .clipShape(Circle())
    }
}

关键点:

  • 主内容使用较大尺寸,次要操作保持 60pt 最小区域
  • 元素间距充足(24pt+),避免误触
  • 使用圆形/圆角形状引导眼睛聚焦中心
  • 避免尖角和粗边框

Hover 效果实现

import SwiftUI

struct HoverButton: View {
    let title: String
    let action: () -> Void
    @State private var isHovered = false
    
    var body: some View {
        Button(action: action) {
            Text(title)
                .padding(.horizontal, 24)
                .padding(.vertical, 12)
        }
        .buttonStyle(.borderedProminent)
        .hoverEffect(.lift)
        // 自定义 hover 效果
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(isHovered ? Color.blue.opacity(0.3) : Color.clear)
        )
        .onHover { hovering in
            isHovered = hovering
        }
    }
}

关键点:

  • 使用 .hoverEffect() 获得系统级 hover 反馈
  • 自定义效果保持微妙,不干扰内容阅读
  • 所有可交互元素都必须有 hover 反馈

深度层级设计

import SwiftUI
import RealityKit

struct DepthHierarchyView: View {
    var body: some View {
        ZStack {
            // 背景内容(稍远)
            ContentView()
                .zOffset(-20)
            
            // 主内容(标准距离)
            MainView()
                .zOffset(0)
            
            // Tab Bar(稍近,表达层级)
            TabBar()
                .zOffset(10)
        }
    }
}

关键点:

  • 交互内容保持在同一深度,减少焦点切换
  • 用 Z 轴微小偏移(10-20pt)表达层级,而非大幅跳跃
  • 模态视图保持与触发元素相同的 Z 位置

直接触摸的反馈补偿

import SwiftUI

struct DirectTouchButton: View {
    let title: String
    @State private var isPressed = false
    @State private var proximity: CGFloat = 0
    
    var body: some View {
        Text(title)
            .padding(.horizontal, 32)
            .padding(.vertical, 16)
            .background(
                RoundedRectangle(cornerRadius: 16)
                    .fill(isPressed ? Color.blue : Color.blue.opacity(0.3 + proximity * 0.4))
            )
            .scaleEffect(isPressed ? 0.95 : 1.0)
            .animation(.easeInOut(duration: 0.1), value: isPressed)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { _ in
                        isPressed = true
                        // 播放空间音效
                        playSpatialSound()
                    }
                    .onEnded { _ in
                        isPressed = false
                    }
            )
    }
    
    func playSpatialSound() {
        // 使用 Spatial Audio API 播放触觉反馈音效
    }
}

关键点:

  • 接近时显示 hover 状态(亮度渐变)
  • 接触瞬间快速响应(0.1s 内)
  • 配合空间音效强化反馈
  • 缩放效果提供视觉确认

核心启发

  1. 为现有 App 重新设计交互流程

    • 做什么:将现有 iOS App 的点击交互改为眼动瞄准 + 手势确认
    • 为什么值得做:visionOS 的眼动瞄准比手指点击更精确,远距离操作更舒适
    • 怎么开始:将按钮改为圆形/圆角形状,确保 60pt 目标区域,添加 .hoverEffect()
  2. 利用眼动意图优化信息展示

    • 做什么:当用户长时间注视某个元素时,自动展示相关详细信息
    • 为什么值得做:减少界面 clutter,需要时才展示信息,保持界面简洁
    • 怎么开始:使用 onHover 配合计时器,注视 1 秒后展开 tooltip 或详情面板
  3. 设计手势优先的 3D 内容操作

    • 做什么:为 3D 模型查看器添加双手缩放/旋转手势,结合眼动确定操作中心
    • 为什么值得做:眼动确定操作原点比手动选择更自然,双手手势符合直觉
    • 怎么开始:使用 RealityKit 的手势识别,将缩放原点设为眼睛注视的模型表面点
  4. 为虚拟键盘优化直接触摸反馈

    • 做什么:在自定义输入界面中实现接近感应、接触响应和空间音效
    • 为什么值得做:缺乏触觉反馈的直接触摸需要多层感官补偿才能感觉可靠
    • 怎么开始:按钮悬浮设计 + 接近高亮 + 接触缩放 + 空间音效组合
  5. 添加 Dwell Control 支持

    • 做什么:确保所有交互元素都支持仅用眼动选择(无需手势)
    • 为什么值得做:运动障碍用户依赖 Dwell Control,这是无障碍合规要求
    • 怎么开始:使用标准 SwiftUI 控件自动获得支持,自定义控件确保有明确的聚焦状态

关联 Session

评论

GitHub Issues · utterances