Discoverable design
Design 入门 18m

可发现性设计

Discoverable design

2021年6月11日

在 Apple 官方观看视频

一句话判断

可发现性(Discoverability)是区分”好用”和”难用”的关键因素 —— 用户不会阅读你的使用说明,所以每个功能都必须有被”偶然发现”的路径,这集 Session 给出了系统性的设计方法。

这场 Session 讲了什么

Session 讲解了”可发现性设计”的原则和实践。可发现性指的是用户在不阅读文档的情况下,通过直觉和探索就能发现 app 功能的能力。

核心论点:用户在使用 app 时分为两种模式 —— “执行模式”(知道自己要做什么,直接操作)和”探索模式”(闲逛、看有什么功能)。好的设计要让探索模式下也能自然发现高级功能。

苹果提出的可发现性设计原则:

  1. 视觉暗示(Visual Cues):用颜色、动画、布局引导用户注意力。不是所有东西都需要突出显示,但关键入口不能隐藏。
  2. 渐进式披露(Progressive Disclosure):先展示基本功能,高级功能在用户需要时才出现。例如长按图标弹出快捷操作、滑动边缘展示侧边栏。
  3. 一致的交互模式:遵循系统约定。下拉刷新、左滑删除、长按预览 —— 用户已经从系统 app 中学到了这些模式。
  4. 反馈闭环:每个操作都有即时视觉反馈,让用户确认”我做对了”。

值得深挖的点

“零教程”原则的工程实现。苹果内部衡量一个功能可发现性的标准是:一个从未用过这个 app 的用户,能在 30 秒内找到并使用这个功能吗?如果答案是否定的,设计需要改。实现方式不是加 tooltip(提示气泡),而是调整视觉层次:让关键功能的按钮更大、颜色更突出、位置更符合手势热区。

触觉反馈(Haptics)在可发现性中的角色。iOS 的 Taptic Engine 可以提供不同类型的触觉反馈:UIImpactFeedbackGenerator(碰撞感)、UINotificationFeedbackGenerator(成功/失败/警告)、UISelectionFeedbackGenerator(选择变化)。恰当的触觉反馈能让用户”感觉到”操作的边界和状态变化,即使视觉上没有明显变化。比如在轮盘选择器中滑动时,每经过一个选项就产生轻触感,用户不需要看数字就能精确选择。

代码片段

渐进式披露的 SwiftUI 实现

import SwiftUI

struct PhotoEditorView: View {
    @State private var showAdvancedTools = false
    @State private var selectedFilter: Filter?

    var body: some View {
        VStack {
            // 主编辑区域(始终可见)
            ImagePreview()
            // 基础工具栏(始终可见,常用功能)
            HStack(spacing: 24) {
                ToolButton(icon: "crop", label: "裁剪")
                ToolButton(icon: "slider.horizontal.3", label: "调整")
                ToolButton(icon: "wand.and.stars", label: "滤镜")
                // "更多"按钮(渐进披露入口)
                Button {
                    withAnimation { showAdvancedTools.toggle() }
                } label: {
                    Image(systemName: "ellipsis.circle")
                        .font(.title2)
                }
                .accessibilityLabel("更多工具")
            }
            .padding()

            // 高级工具(按需展示)
            if showAdvancedTools {
                AdvancedToolsPanel(selectedFilter: $selectedFilter)
                    .transition(.move(edge: .bottom).combined(with: .opacity))
            }
        }
    }
}

触觉反馈增强可发现性

import SwiftUI

struct SegmentedValuePicker: View {
    let values: [String]
    @State private var selectedIndex = 0

    var body: some View {
        ScrollViewReader { proxy in
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    ForEach(Array(values.enumerated()), id: \.offset) { index, value in
                        Text(value)
                            .padding(.horizontal, 20)
                            .padding(.vertical, 10)
                            .background(selectedIndex == index ? Color.blue : Color.clear)
                            .foregroundColor(selectedIndex == index ? .white : .primary)
                            .clipShape(RoundedRectangle(cornerRadius: 8))
                            .onTapGesture {
                                selectedIndex = index
                                // 触觉反馈:让用户"感觉"到选择了
                                UISelectionFeedbackGenerator().selectionChanged()
                                // 视觉反馈:滚动到选中项
                                withAnimation {
                                    proxy.scrollTo(index, anchor: .center)
                                }
                            }
                            .id(index)
                    }
                }
            }
        }
    }
}

上下文相关的功能提示

import SwiftUI

struct ContextualTipView: View {
    let tip: Tip
    @State private var isVisible = true
    @AppStorage("hasSeenSearchTip") private var hasSeenSearchTip = false

    var body: some View {
        if isVisible && !hasSeenSearchTip {
            HStack {
                Image(systemName: "lightbulb.fill")
                    .foregroundColor(.yellow)
                Text(tip.message)
                    .font(.subheadline)
                    .foregroundColor(.secondary)
                Spacer()
                Button {
                    withAnimation { isVisible = false }
                    hasSeenSearchTip = true
                } label: {
                    Image(systemName: "xmark.circle.fill")
                        .foregroundColor(.secondary)
                }
            }
            .padding(12)
            .background(Color(.systemGray6))
            .clipShape(RoundedRectangle(cornerRadius: 10))
            .transition(.opacity)
        }
    }
}

struct Tip {
    let message: String
    static let searchSwipe = Tip(message: "试试在列表中向下滑动来搜索")
    static let longPressPreview = Tip(message: "长按任意项目可以快速预览")
}

最佳实践

  1. 功能入口的点击热区要够大。苹果推荐最小 44x44 点的触摸目标。在小屏设备上,过小的按钮不仅难点击,更难被”发现”。
  2. 动画引导注意力。当页面有新内容出现时,用轻微的弹跳动画(spring response)而非静态切入。人眼天生对运动敏感。
  3. 不要用 tooltip 作为可发现性的唯一手段。Tooltip 只在用户 hover/长按时出现,这意味着用户必须先知道”这里有东西可以长按”。更好的方式是让功能本身可见,用视觉暗示表明它可以交互。

还有什么值得关注

  • 苹果在人机界面指南(HIG)中新增了”Discoverability”章节,提供了更多设计案例。
  • UIContextMenuInteraction(长按菜单)是渐进式披露的经典模式,适合把二级操作藏在长按菜单中。
  • ONboarding 流程中的”功能亮点”提示应该控制在 3 个以内,超出就会被用户跳过。
WWDC 2021