大多数浏览器和
Developer App 均支持流媒体播放。
-
了解 SwiftUI 中的辅助功能
SwiftUI 让你能够轻松打造人人可享的出色体验。我们将探索辅助技术如何通过 SwiftUI 提供的丰富辅助功能元素来理解和操作你的 App。我们还将讨论如何使用辅助功能修饰符提供有关 App 内容和交互的更多信息,来进一步自定这类体验。
章节
- 0:00 - Introduction
- 0:58 - Fundamentals
- 9:01 - View accessibility
- 16:28 - Enhanced interactions
资源
-
下载
嗨 我叫 Tommy 是辅助功能团队的工程师 辅助功能是很多优质 App 很基础的一环 它让每个人都能借助你构建的体验 尽情创造、沟通和娱乐 SwiftUI 可帮助你在 Apple 各个平台上生动呈现这些体验 今天我们来深入了解一下 SwiftUI 如何为你提供 开箱即用的内置辅助功能 以及有助于改进和定制 App 辅助功能的工具
然后我们会讨论在哪些场景下 需要向 SwiftUI 提供更多信息 以改进你的视图的辅助功能
最后我们将探索如何 为轻点、拖放等交互方式 构建丰富的无障碍体验
SwiftUI 从一开始就为 内置视图提供了辅助功能支持 同时可让你轻松为辅助功能技术 提供更多信息 从而优化 App 的使用体验 我一直在用 SwiftUI 打造一个 App 来分享我最喜欢的回忆:海滩之行 在这个 App 中 我可以发送消息 描述美丽的海洋景致 而且只需轻点一下 我就可以附上地点信息、 海浪的录音或是给海滩打分 每个人都可以对这趟旅行发表评论 而我可以给评论点赞 和回复评论
我甚至还可以为不同朋友的回复 创建自定声音!
这非常棒 我们来探索一下 SwiftUI 如何让这些功能实现无障碍访问 SwiftUI 会创建辅助功能元素 这是它的主要输出之一 辅助功能元素是一种基本构建块 “旁白”、“语音控制”和 “切换控制”等辅助功能技术 会利用这种元素来呈现 App 中的内容 并与内容进行交互 辅助功能元素可代表一个或多个视图 而且提供属性和操作 属性用于描述视图的内容 操作用于公开 如何通过轻点以及复杂手势 与视图交互
“旁白”这类辅助功能技术 仅可通过元素 与 App 交互 因此只能访问 包含在元素里的视图内容
这是开关视图 用于控制我朋友是否可以 对我发布的旅行发表评论
这个开关是在我的视图主体中声明的 SwiftUI 利用它来生成输出 包括屏幕上显示的内容 和辅助功能元素
对于辅助功能元素 Comments 标签 用于创建元素的标签 isToggle 和 isSelected 特征 会被应用于这个元素 press 操作用于切换这个设置
当“旁白”专注于开关时 这个元素会被描述出来 轻点两下就能执行 press 动作 “设置 标题 评论 开关按钮关闭 打开”
SwiftUI 将文本 和开关合并为单个元素 多个视图能够以单个元素表示 从而简化导航 并将相关信息联系起来 在自定开关的外观和风格 以适应我的 App 时 保留元素的属性和操作非常重要 SwiftUI 强大的视图样式系统 是实现这一目标的关键 让你既能改变视图外观 又能保留内置辅助功能支持
即使在改变视图的视觉样式时 属性和操作也会应用于视图
当使用切换样式修饰符改变样式时 开关的视觉效果会更新 但相应的元素会保留标签和特征
当用户轻点自定开关时 相应元素的属性会反映开关的新状态
视图样式兼容许多不同的控件 比如按钮和开关 也兼容分组 比如标签和带标签内容 还兼容指示器 比如进度视图和仪表 尽可能使用样式系统 而不是创建自定视图 否则 你将不得不重新应用 那些你本可以 自动获取的辅助功能属性 使用样式和内置视图将为你的 App 提供出色的辅助功能体验 注意 向 SwiftUI 提供的 辅助功能相关信息越多 用户体验就会越好 你可以使用辅助功能修饰符 来提供这些信息
辅助功能修饰符让你可以自定义 通过辅助功能元素 展现视图的方式 视图中可以添加标签或特征等属性 还可以公开自定手势等交互操作
修饰符甚至让你可以 将多个视图合并到单个元素中 以改善导航
在使用修饰符来自定义 视图的辅助功能之前 了解你可以在哪些地方 改善 App 体验的最佳方式 是借助“旁白”等技术 来使用辅助功能
让我们在我的 App 中用“旁白” 来查看最近的一次海滩之旅 以了解有哪些可以改进的地方
“周末探险 标题” “星期六 这是个美好的周末! 风平浪静 阳光照耀在桥上 天空万里无云 图片” “看上去很开心呢 点赞 按钮 回复 按钮 Nick”
“太漂亮了 点赞 按钮 回复 按钮 Jack”
SwiftUI 为我的 App 打造了良好的体验 “旁白”能够浏览所有内容 还做出了一些优化 比如针对标题 和按钮描述了指示器 不过我注意到有三点可以改进的地方 首先 评论部分由于元素众多 需要花很长时间来浏览 而且用户很快就不知道 每个评论对应的是哪个按钮了 还有一些视图 例如我的未读指示器 旁白并未描述这些内容 我们来看看如何才能让 这体验变得更好吧
这是我的评论视图 这里是元素的水平堆栈 代表评论消息 包含一个未读指示器以及 用于回复和点赞评论的两个按钮 SwiftUI 为这个视图创建了三个 辅助功能元素 一个针对标题 两个针对操作按钮 我的堆栈和间隔视图 不是元素 因为它们只控制 我视图的视觉布局 默认情况下 未读指示器 没有辅助功能元素 因为它是以形状视图表示的 所以我们先添加一个标签 来描述评论是否为未读
辅助功能标签修饰符 会首先为我的指示器视图 创建一个元素 因为它默认没有元素 然后会将这个元素的标签 设置为未读
当指示器视图为未读时 这个元素将始终对辅助功能技术可见 当评论变为已读时 SwiftUI 会提供帮助 当评论处于已读状态时 指示器的不透明度变为零 从而在视觉上隐藏 SwiftUI 也会自动将这个元素 对辅助功能技术隐藏
为了简化评论视图的导航 我可以将每个堆栈设为单个元素 并将我的每个按钮 转变为这个元素的操作 通过应用 .accessibilityElement(children: .combine) 修饰符 多个元素的属性和操作 就可以组合在一起
这个元素的标签将是 所有视图的组合标签 重要的特征将合并到一起 而来自按钮等控件的操作 将转变为自定操作 现在单个元素用来表示消息、 消息是否未读 以及相应的操作 这使得浏览我的评论变得轻松多了 当我再用“旁白”来浏览每条评论时 体验更棒了 描述变得更容易理解了 “未读 看上去很开心呢 Nick 按钮” “点赞 回复”
SwiftUI 帮我分担了繁重的工作 使我的视图可以无障碍访问 尽管如此 在适当的情景中 为辅助功能技术 提供更多信息可修复缺失的内容 并提供更愉悦的体验 我的海滩之旅消息体验 已经有了很大的改善 但我希望特别关注一些朋友的评论
在 App 界面中 当我轻点两下 一条已点赞的评论 它就会变成“超赞” 超赞会使用一个新的标志 来表明评论的关注度 但这个变化会带来一个新问题 之前 我合并的点赞操作 已经正确地设置了标签 但现在“旁白”会把 超赞的名称读成闪光 “未读 太漂亮了 Jack 按钮”
“点赞” “回复” “未读 希望你涂了防晒霜 Beth 按钮”
“闪光 回复”
在视图中使用符号时 如果可以推断出符号的含义 例如星形或回复符号 许多符号会提供默认的标签 而其他符号如果代表特定的内容 则需要添加显式标签 否则将回退到使用符号名称作为标签 即使在视图中使用了 某个符号的默认标签 也要始终尝试借助辅助功能技术 来验证实际使用效果 以保证能准确地描述你的界面 对于超赞 我只需更新 标签错误的闪光符号
我可以使用修饰符来添加 辅助功能标签 但应用这一标签后 它会覆盖评论没有获得超赞时 SwiftUI 已经提供给我们的 正确默认标签
在 iOS 18 中 现在可将 isEnabled 参数添加到辅助功能修饰符中 如果修饰符状态为已启用 属性就会应用于视图 如果状态是未启用 修饰符就不会生效 在这里 只有当评论获得超赞时 才会应用超赞标签 当评论未获得超赞时 SwiftUI 将回退到使用 星型符号的默认标签 SwiftUI 默认为你提供 合适的辅助功能支持 这点很棒 但有时你需要根据情况进行自定义
回到我 App 中的评论视图 超赞操作回来了 而且完美地添加了标签 “未读 希望你涂了防晒霜 Beth 按钮” “超赞 回复”
除了始终应该添加缺失的信息 比如标签 提供更简便的方式 来呈现需要多次交互 才能获取的信息 也可为你的 App 提升 辅助功能技术使用体验 许多应用场景都是探索 这些增强功能的好机会 尤其是当悬停光标、按键操作或手势 会让视图动态出现时 我一直在努力将 我的 App 移植到 macOS 而我想添加一个很棒的交互 那就是悬停来显示旅行相关附件
当鼠标悬停在旅行图像视图上时 会显示一组附件按钮 包括地点信息、录音和海滩评分 这会消除冗余的内容 让用户 专注于美丽的海滩照片 但为确保这些附件可以无障碍访问 有一些要考虑的事项 动态显示的内容 比如支持悬停操作的视图 借助辅助功能技术 或使用键盘或开关等 触控屏以外的替代输入源来导航时 可能需要更长的时间
当移动鼠标光标时 显示视图和完成交互 只需几秒钟
但是“旁白”需要很多步 才能导航至这个视图 首先需要将焦点放在可悬停视图上 接着通过命令触发悬停操作 等到视图出现 需要导航到子视图 然后等交互结束后 焦点必须返回到原始视图
通过将可悬停视图的 辅助功能属性和操作 附加为主视图的一部分 可以简化这种交互
并非每次旅行都有 录音或位置信息附件 因此要添加到旅行视图的操作 或标签的确切数量并不是固定的 SwiftUI 提供了适合 这些情况的辅助功能修饰符 我们从操作说起
这里显示的是旅行视图的 可悬停叠加层 为了让这些控件更易于使用 我可以将控件转化为旅行视图上的 自定操作
辅助功能操作修饰符 接受用于显示旅行附件的同一视图 它会提取控件并将控件转换为 我旅行视图上的自定操作 现在 叠加层 和旅行视图的自定操作 可采用相同的逻辑 通过这一更改 “旁白”现在可以执行每个附件 而无需呈现叠加层
“星期六 这是个美好的周末! 风平浪静 阳光照耀在桥上 天空万里无云 图片” “操作菜单 2 项 位置信息 录音”
这里漏了一项 也就是我对海滩的评分 评分会在悬停时显示 由于它是这场旅行的关键信息 所以我想让评分在旅行 辅助功能元素中更加醒目
当用户需要多次交互 才能获取重要信息时 可以考虑将这些信息附加到 视觉上虽未显示信息 但更容易导航到的元素中 如果你修改了某个元素的属性 比如组合多个元素 你可能需要考虑 把象征内容的装饰性视图 提供的附加内容包含进去
这两种情况都需要 为内容可能并不固定的视图 修改标签 SwiftUI 提供了 应对这两种情况的工具
我想将评分附加到旅行元素的标签 以简化用“旁白”查找评分的过程
常规的标签修饰符会抹掉 SwiftUI 已经提供给这个元素的 合理描述内容 而由于评分只是有时才出现 我只想将它包含在某些消息里
辅助功能标签修饰符 现在也可以接受视图 并且会从视图中提取文本 并将文本设置在旅行元素的标签上 它甚至还为视图的现有标签 提供了一个占位符 这样一来 我的旅行评分就能 与 SwiftUI 为旅行元素 创建的现有标签结合起来
回到旅行视图 “旁白”现在可以正确地将评分 和旅行的帖子作为 一个完整的标签来朗读了 “半颗星 星期六 这是个美好的周末! 风平浪静 阳光照耀在桥上 天空万里无云 图片”
听起来不错 悬停只是可以考虑 使用这些 API 的开始 做出任何内容上的改动时 都请确保 “旁白”等技术可以访问改动后的内容
在为你的 App 构建交互功能时 很重要的一点是谨记 为触控屏或鼠标以外的替代输入方式 设计出色的体验
在你构建的众多体验中 占据核心地位的一种交互 就是拖放
“旁白”和“语音控制”等 辅助功能技术支持拖放 而且 SwiftUI 支持使用 onDrag 和 onDrop 修饰符 构建无障碍使用体验
拖放的界面很灵活 所以有一些方法可以 提升你的 App 带来的体验 我的 App 使用拖放功能来创建 好友评论时的自定提醒 我们来用“旁白”试一下 我可为一个联系人拖动 最多 3 种声音来创建提醒 我使用自定放置委托来允许 同一视图中存在多个放置点 但这样一来 “旁白”无法判断 可以在哪几个地方放置声音 “合成 可拖移” “拖移”
“欢呼 可拖移 提醒 无声音”
“放置 放置就绪” “放置完成”
辅助功能拖放点修饰符 可定义你的视图上 支持拖放的点 在评论提醒视图中 我定义了三个放置点 用来描述可以设为提醒的 三种不同声音 每个点还提供了一个标签 用来描述 需要执行的交互 现在“旁白”可以访问 提醒视图上的每个放置点 “合成 可拖移” “拖移”
“欢呼 可拖移 提醒 钟声 鸟叫声” “放置 放置就绪 设置声音 3 放置就绪”
“放置完成”
新的体验非常棒 我可以在 App 中快速拖移声音 为联系人设置自定提醒
构建拖放体验时 很重要的一点是 要经常用辅助功能技术 来试用你的体验 从而确保 体验中提供的功能确实可用 你可能还需要考虑 除拖放之外的自定操作 特别是当可进行拖移的 位置或操作有限时
此外 如果一个元素 支持在不同的点进行多次交互 还应确保将其中的每个点 都公开给辅助功能技术 交互可扩展到 App 边界之外 变为交互式小组件 在小组件中 视图不会实时更新 因此无法使用 辅助功能操作修饰符 App Intents 允许使用 按钮和开关等小组件 来创建交互式视图 但在小组件中可能有一些地方 可以通过额外的自定操作 来提升用户体验 我正在为我的 App 开发 一个新的小组件 以便快速评价和发帖分享 我喜欢去的海滩 只需轻点一下 我甚至可以更新 最喜爱海滩的排名 SwiftUI 会为每个按钮提供标签 而且可以使用“旁白”激活这些按钮
这是我的海滩视图 有三个交互式按钮 可发帖分享海滩和进行排名 我想用自定操作来执行 我的小组件中最重要的功能 从而让小组件的使用体验变得更棒
辅助功能操作修饰符 现在接受 App Intent 会在调用时执行意图 并更新你的小组件
这里我添加了一个自定操作 可将某个海滩设为我的最爱 还有一个神奇的轻点操作 只需轻点两下就能拍照
有了这些改变 我现在可以标记我最爱的海滩 然后它就会移到列表顶部 “方斯顿海滩 无评分 按钮” “贝克海滩 无评分 按钮” “设为最爱”
“贝克海滩 最爱 按钮” 我们介绍了如何为你的 App 引入辅助功能 请确保 借助“旁白”等辅助功能技术 来试用你的 App 探究辅助功能 API 可在哪些方面让你的 App 有更好的使用体验 并探索辅助功能示例项目 更好地了解 可如何使用辅助功能 API 来优化 SwiftUI 中的常见模式 我们辅助功能团队迫不及待 想看到大家为自己的 App 打造出色的辅助功能体验 感谢观看
-
-
7:27 - Accessibility Label Modifier & Opacity
struct UnreadIndicatorView: View { var isUnread: Bool var body: some View { Circle() .foregroundStyle(.blue) .accessibilityLabel("Unread") .opacity(isUnread ? 1 : 0) } }
-
8:02 - Accessibility Element Children Combine Modifier
var body: some View { HStack { UnreadIndicatorView(isUnread: message.isUnread) MessageContentsView(message: message) Spacer() Button(action: favorite) { favoriteLabel } Button(action: reply) { replyLabel } } .accessibilityElement(children: .combine) }
-
10:37 - Accessibility Conditional Modifiers
var body: some View { Button(action: favorite) { Image(systemName: isSuperFavorite ? "sparkles" : "star.fill") } .accessibilityLabel("Super Favorite", isEnabled: isSuperFavorite) }
-
13:38 - Accessibility Actions Modifier
var body: some View { TripView(trip: trip) .onHover { showAttachments = $0 } .overlay { MessageAttachments(attachments: trip.attachments) .opacity(showAttachments ? 1 : 0) } .accessibilityActions { MessageAttachments(attachments: trip.attachments) } }
-
15:16 - Accessibility Label Modifier
var body: some View { TripView(trip: trip) .accessibilityLabel { label in if let rating = trip.rating { Text(rating) } label } }
-
17:42 - Accessibility Drop Point Modifier
var body: some View { CommentAlertView(contact: contact) .onDrop(of: [.audio], delegate: delegate) .accessibilityDropPoint(.leading, description: "Set Sound 1") .accessibilityDropPoint(.center, description: "Set Sound 2") .accessibilityDropPoint(.trailing, description: "Set Sound 3") }
-
19:45 - Accessibility App Intent Action Modifier
var body: some View { ForEach(beaches) { beach in BeachView(beach) .accessibilityAction( named: "Favorite", intent: ToggleRatingIntent(beach: beach, rating: .fullStar)) .accessibilityAction( .magicTap, intent: ComposeIntent(type: .photo)) } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。