WWDC Quick Look 💓 By SwiftGGTeam
The process of inclusive design

The process of inclusive design

观看原视频

Highlight

Apple 把包容性设计定义为贯穿团队、调研、设计、开发、测试、发布和迭代的工作流程,帮助开发者在早期发现不同人群的真实需求,减少发布后才修补体验缺口的成本。

核心内容

一个团队做应用时,最容易从自己熟悉的用户开始。团队成员住在同一类城市,使用同一类网络,读同一种语言,拥有相近的身体能力和文化经验。需求评审时,大家会觉得产品已经覆盖主要场景。

问题通常到发布后才暴露。有人在低速网络下无法完成关键流程。有人使用 VoiceOver(屏幕阅读器)时听不到自定义控件的含义。有人看到照片回忆里的前伴侣或逝去亲人,原本温暖的功能变成压力来源。

Apple 在这场演讲里没有发布单个新框架。它给出一套流程:先用 diversity axes(多样性维度)扩展视角,再把包容性检查放进构思、设计、开发、测试、发布和发布后的迭代。

这套方法解决的是时机问题。包容性如果只在上线前检查,很多设计已经很难改。发布日、资源和架构都会变成约束。把它放到每个阶段,团队就能更早决定要听谁的反馈、要保留哪些时间、要砍掉哪些做不到位的功能。

从团队开始

Apple 强调,拥有多元团队还不够。团队成员需要被邀请表达不同观点,这些观点还要进入决策。小团队尤其要早做这件事,因为早期招聘会把文化和产品假设固定下来。

一个直接做法是把“culture fit”改成“culture add”。招聘和协作时,问缺少什么视角,避免只寻找最像现有团队的人。

从流程开始

包容性流程像安全和隐私一样,需要预留时间。构思阶段问产品服务什么 human good(人的益处)。设计阶段检查极端使用场景。开发阶段提前规划 Accessibility(无障碍)和 Internationalization(国际化)。测试阶段让使用辅助技术和不同背景的人参与。发布阶段明确取舍,并给未解决问题设定计划。

从真实反馈继续迭代

Photos Memories(照片回忆)的例子说明,发布之后还要继续迭代。有人希望系统生成更多兴趣和节日主题,团队就扩大运动、爱好和国际节日目录。有人不想被提醒某个人,团队就加入 Feature Less(少展示)和 Never Feature Again(不再展示)的控制。

这类改动来自具体反馈。团队先听故事,再设计方案,再回到受访者那里验证。

详细内容

多样性维度:先承认默认视角很窄

00:53)Apple 建议团队围绕多样性维度思考用户。演讲列出的维度包括阶层、文化、民族、语言、教育、信仰、种族、性别、性取向、年龄、能力、残障、惯用手、身高,以及地点、网络连接和设备访问条件。

let diversityAxes = [
    "class",
    "culture",
    "ethnicity",
    "language",
    "education",
    "beliefs",
    "race",
    "gender",
    "sexualOrientation",
    "age",
    "abilitiesAndDisabilities",
    "handedness",
    "bodyMeasurements",
    "location",
    "internetConnectivity",
    "deviceAccess"
]

func reviewQuestion(for axis: String) -> String {
    "What will the experience be for people across \(axis)?"
}

for axis in diversityAxes {
    print(reviewQuestion(for: axis))
}

关键点:

  • diversityAxes 来自演讲开头列出的多样性维度。
  • language 提醒团队检查文案、本地化和输入格式。
  • abilitiesAndDisabilities 对应无障碍设计和辅助技术测试。
  • internetConnectivity 对应低速网络、离线和流量受限场景。
  • reviewQuestion(for:) 把抽象维度变成评审问题。
  • for axis in diversityAxes 让每个维度都进入产品评审,避免只检查团队最熟悉的人群。

这段代码适合放进设计评审脚本或 PR 模板生成器。它的作用是提醒团队:每次新增核心流程,都要明确哪些维度已经检查,哪些维度还缺证据。

构思阶段:先回答为什么做、给谁用

09:32)在构思阶段,Apple 给出两个问题:为什么做这个应用或游戏,以及它面向谁。团队要说明它服务什么人的益处,帮助人们做什么、成为什么或感受到什么。

struct ProductIdeaReview {
    let purpose: String
    let humanGood: String
    let targetPerspectives: [String]

    var isReadyForDesign: Bool {
        !purpose.isEmpty && !humanGood.isEmpty && !targetPerspectives.isEmpty
    }
}

let review = ProductIdeaReview(
    purpose: "Help people revisit meaningful photos and videos.",
    humanGood: "Enable people to relive moments they care about.",
    targetPerspectives: [
        "people with different hobbies",
        "people celebrating regional holidays",
        "people with difficult memories around specific people"
    ]
)

print(review.isReadyForDesign)

关键点:

  • purpose 对应“Why are you making this?”。
  • humanGood 对应演讲里的“what human good are you trying to serve?”。
  • targetPerspectives 要写具体人群和情境,不能只写“所有用户”。
  • isReadyForDesign 要求三个字段都有内容,避免团队带着空泛目标进入设计。
  • 示例里的照片回忆场景来自演讲后半段的 Photos Memories 案例。

这个模型可以用在产品需求文档里。每个新功能开工前,先让负责人填完这三个字段。填不出来,就需要继续访谈或缩小范围。

开发阶段:提前规划无障碍和国际化

12:23)Apple 提醒开发者在开发开始时规划无障碍和国际化。标准 UIKit、AppKit 和 SwiftUI 控件默认实现 UIAccessibility(无障碍接口)方法;自定义控件和视图需要预留更多时间。

import SwiftUI

struct ReminderSettingsView: View {
    @State private var isEnabled = true

    var body: some View {
        Form {
            Toggle("Show Memories", isOn: $isEnabled)
            Text("Use standard SwiftUI controls before building custom controls.")
        }
    }
}

关键点:

  • import SwiftUI 引入 SwiftUI 框架。
  • ReminderSettingsView 是一个普通设置页示例。
  • Toggle 是标准 SwiftUI 控件,演讲指出标准 SwiftUI 控件默认支持无障碍。
  • Text 使用系统文本控件,能进入系统的文本和无障碍体系。
  • Form 使用平台标准表单结构,减少自定义布局带来的无障碍成本。
  • 这段代码没有创建自定义控件,因为演讲提醒自定义控件需要额外规划和测试。

开发时先优先使用系统控件,减少每个界面的复杂适配。只有确实需要自定义控件时,再把 VoiceOver 标签、焦点顺序、动态字体和键盘导航列入开发任务。

机器学习功能:图像描述要处理交叉身份

14:56)Apple 介绍了 iOS 15 的 Markup Description(标记描述)功能,用户可以给照片写自己的描述;VoiceOver Recognition(旁白识别)也能用机器学习为图像生成自然语言描述。团队随后发现,模型描述人的性别时需要谨慎,因为只看照片无法知道一个人的性别。

struct ImageDescriptionInput {
    let hair: String
    let clothing: String
    let setting: String
}

func genderNeutralDescription(for input: ImageDescriptionInput) -> String {
    "A person with \(input.hair) wearing \(input.clothing) and standing \(input.setting)."
}

let input = ImageDescriptionInput(
    hair: "curly black hair",
    clothing: "a red and white striped shirt",
    setting: "in front of a building"
)

print(genderNeutralDescription(for: input))

关键点:

  • ImageDescriptionInput 只保存可从照片中描述的外观信息。
  • hair 对应演讲示例里的 “curly black hair”。
  • clothing 对应演讲示例里的 “red and white striped shirt”。
  • setting 对应演讲示例里的 “in front of a building”。
  • genderNeutralDescription(for:) 使用 A person,符合团队最后采用的性别中性描述方向。
  • 代码没有推断 malefemalenon-binarytransgender,因为演讲明确说不能通过照片知道一个人的性别。

这个例子适合机器学习功能的输出后处理。模型可以识别衣服、发型和场景,但产品文案要避免把无法确定的身份写成事实。

测试阶段:把辅助技术写进测试计划

21:34)测试阶段要让不同背景的人使用产品,并加入辅助技术和各种 accommodations(调适方式)。演讲给出三个可直接执行的检查项:学习 VoiceOver 基础、把文字调到最大、用键盘导航应用或游戏。

let inclusiveTestPlan = [
    "Navigate every primary flow with VoiceOver",
    "Increase text size to the maximum level",
    "Navigate the app or game with the keyboard",
    "Collect feedback from testers with diverse backgrounds",
    "Review and prioritize feedback before release"
]

for item in inclusiveTestPlan {
    print("[ ] \(item)")
}

关键点:

  • VoiceOver 来自演讲的测试建议。
  • maximum level 对应把文字大小调到最大。
  • keyboard 对应用键盘导航应用或游戏。
  • diverse backgrounds 对应让不同背景测试者发现边缘场景。
  • Review and prioritize feedback 对应演讲里的“listen, review, and prioritize feedback”。
  • print("[ ] ...") 可以生成发布前检查清单。

这类清单应该进入测试计划,不能留给上线前的个人记忆。Apple 还建议把包容性测试目标作为 KPI(关键绩效指标)跟踪。

发布后:Photos Memories 用反馈改变产品控制权

24:31)Photos Memories 团队收到两类反馈。一类用户希望看到更多爱好和节日主题,团队扩展了武术、滑板、足球,以及 Diwali、Lunar New Year、Eïd al-Fitr、Hanukkah 等节日。另一类用户不想被提醒某个人,团队加入了对人物出现频率的控制。

enum MemoryPersonPreference {
    case featureLess
    case neverFeatureAgain
}

struct MemoryFeedbackResponse {
    let personName: String
    let preference: MemoryPersonPreference
}

let response = MemoryFeedbackResponse(
    personName: "Alex",
    preference: .neverFeatureAgain
)

print(response.preference)

关键点:

  • MemoryPersonPreference 把演讲中的两种迭代结果写成状态。
  • .featureLess 对应少展示某个人。
  • .neverFeatureAgain 对应不再展示某个人。
  • MemoryFeedbackResponse 表示一次用户反馈带来的产品设置。
  • personName 在真实产品里应来自用户自己的照片人物库。
  • 示例保留两档控制,因为演讲提到不同人对回忆内容有不同容忍阈值。

32:39)团队还发现 thumbs down(拇指向下)图标会让人感觉是在讨厌某个人。对逝去亲人这类场景,这个含义会伤害用户。最后团队选择了更中性的 glyph(符号)。

let rejectedGlyph = "hand.thumbsdown"
let selectedGlyph = "minus.circle"

func glyphForSensitivePreference() -> String {
    selectedGlyph
}

print(glyphForSensitivePreference())

关键点:

  • rejectedGlyph 表示团队不再采用的负面图标方向。
  • selectedGlyph 表示更中性的图标方向。
  • glyphForSensitivePreference() 把选择集中起来,便于设计和开发共同评审。
  • 这个例子提醒开发者:图标本身也是文案,会传达态度。

这个案例的重点是闭环。团队先读评论,再访谈,再设计,再把草图拿回给受访者验证。第一版反馈不够,就继续迭代。

核心启发

1. 做一个发布前包容性检查页

  • 做什么:在内部工具里为每个版本生成一页检查清单,覆盖多样性维度、VoiceOver、最大字号、键盘导航、低速网络和本地化。
  • 为什么值得做:演讲强调包容性要贯穿流程,不能只在发布前临时补救。
  • 怎么开始:用 diversityAxes 数组生成 PR 模板或 Release Checklist,把每项检查绑定负责人和截止日期。

2. 给用户内容加入“少出现”和“不再出现”控制

  • 做什么:在照片、日记、社交回顾、音乐回顾等功能里,让用户控制某个人、地点或主题的出现频率。
  • 为什么值得做:Photos Memories 说明,自动回忆可能触发困难经历。控制权可以减少伤害。
  • 怎么开始:先定义类似 MemoryPersonPreference 的枚举,再把偏好用于推荐、排序或过滤逻辑。

3. 做一个图片描述编辑器

  • 做什么:允许用户给上传图片补充文字描述,并在分享时带上描述。
  • 为什么值得做:演讲提到 iOS 15 的 Markup Description 可以让照片描述随分享传递,帮助盲人或低视力用户理解图片。
  • 怎么开始:在图片上传流程增加 description 字段,提供预览,要求描述聚焦可确认的内容,避免推断身份。

4. 为机器学习输出加一层包容性审核

  • 做什么:对图像描述、推荐理由、自动标签等机器学习输出做规则审核,过滤无法从输入中确认的身份判断。
  • 为什么值得做:VoiceOver Recognition 团队发现,性别中性图像描述可以服务盲人或低视力用户,也能尊重不同性别身份。
  • 怎么开始:先收集模型输出样本,标记涉及性别、年龄、种族、文化的词,再写后处理规则和人工评审流程。

5. 把用户访谈变成迭代入口

  • 做什么:针对负面反馈安排一对一访谈,记录具体时刻、感受和改进建议,再用原型回访。
  • 为什么值得做:Photos Memories 团队通过访谈发现第一版 Feature Less 不够,随后增加 Never Feature Again。
  • 怎么开始:在反馈后台增加标签,筛出“感到不被包含”“被错误提醒”“无法使用辅助技术”的案例,优先约访。

关联 Session

评论

GitHub Issues · utterances