大多数浏览器和
Developer App 均支持流媒体播放。
-
在你的 app 中支持硬件键盘
用户在你的 app 中使用硬件键盘时,不仅可以获得更具触觉和更熟悉的打字体验,而且还可以快速导航或使用键盘快捷指令。探索如何让 iPadOS 和 Mac Catalyst app 更好地支持硬件键盘:我们将揭开 responder chain 的神秘面纱,并向你展示实现自定义键盘快捷指令的最佳方法。了解如何轻松启动和运行常见的系统键盘快捷指令,使用带有手势识别的修改标志,并利用原始键盘事件 API 响应按下按键和松开按键事件。
资源
相关视频
WWDC22
WWDC21
WWDC20
WWDC19
-
下载
(你好 WWDC 2020)
你好 欢迎来到 WWDC (在你的 app 中支持硬件键盘) 我是 James Magahern 来自于 iOS 键盘团队 很高兴我能在这里做一个简短介绍 关于如何使你的 app 在设备中成为一个 带有硬件键盘的一等 app
iOS 应用程序一直围绕 Touch 采用用户界面 这是一个绝佳的、与内容交互的方式 在你的 app 中探索发现用户界面 就和屏幕上显示信息一样简单 然而 有硬件键盘的 iPad 用户 变得十分普遍 在你的 app 中支持硬件键盘 允许你的用户变得更加有效率 并且也能更快速和符合人体工程学地 导航你的用户界面 它们可以利用肌肉记忆来执行功能 甚至不需要思考 另外 通过实现标准快捷方式 新手用户可以使用 Mac 设计好的 熟悉一致的界面 访问你的 app 在下一代的计算机平台中成为一流的 app 就像 iPad 一样 你的 app 应该 在 Touch 和硬件键盘交互两方面 都做到突出
这是对我们今天要讲的内容的一个 快速地预览 让我们直接从聊一聊键盘快捷方式开始吧 讲到键盘快捷方式如何在 iOS 中工作 那我们就要先来聊一聊 UIKeyCommand UIKeyCommand 是一个对象 它在你的 app 中代表了 一个自定义键盘快捷键 它有着你所期待的所有性能 比如展示给用户的可发现标题 调用它时所需要的键盘输入 以及选择性地 决定应该保留那些修改键的 一系列 modifierFlags 这些都一起存在在你的用户界面中 通过一个在 UIResponder 中的 叫做 keyCommands 的可重写属性 返回键命令数组 你可以在 UIResponder 中 为了某个特定响应 返回所有命令的数组 最常见的 UIKit 小部件 已经是 UIResponder 的子类了 所以 在大多数例子中 扩展你的 app 以包含这些关键命令 应该和重写这一个属性一样简单 而返回任意键命令 与用户界面的特定部分相关 这些全部都适配进你的 app 的方式是 通过响应程序链 响应程序链松散地 遵循应用程序的视图层次结构 在末端是 UIApplication 实例 在开始是用户当前正在与之交互的 响应程序 你的 app 的第一个响应程序是 UIResponder 对象 所有的键盘事件都首先进入它 如果链中的一个响应程序 无法处理特定事件 这个事件会在链中继续被推进 例如 UIViews 让它们指定的下一个响应程序 作为视图的超级视图
然后应用程序从每个响应程序 收集关键命令 通过你重写的 keyCommands 方法 由 app 的第一响应程序开始 到高级 UIApplication 实例结束 一旦你的所有关键命令都被系统所收集 用户将可以通过可发现性抬头显示器 发现它们 它可通过在系统的任意地方 按住命令键进行访问 这很棒 不仅因为你的用户可以发现键盘快捷方式 还因为它在开发过程中很应手 能够在一个地方测试和检查所有的设备
现在让我们看一看这些如何在实践中呈现 让我们用音乐 app 作为一个例子 当音乐 app 在前台时 用户可以按空格键 轻松地切换现在正在播放的歌曲 这始终适用于 所有支持任意种类媒体播放的 app 比如当在 Photos app 中播放照片时 或者在 Safari 浏览器中 播放 QuickTime 视频 遵循模型视图控制器模式 定义此行为的理想位置 是在你的自定义视图控制器子类中 在这个例子中 我们有一个 UIViewController 的 播放器视图控制器子类 它管理应用程序中的播放 以及视图中包含播放按钮之类的内容 由于所有的 UIControllers 都是 UIResponders 我只需要在这里重写几个方法 来允许它开始接受键盘快捷键 首先 重写 canBecomeFirstResponder 并返回 true 接着 重写 viewDidAppear 并访问 becomeFirstResponder 以确保此视图控制器首次出现时 是第一响应程序 最后 重写 keyCommands 性能 来返回我们的自定义空格键盘快捷键 这里 你可以看到 我们提供了一个本地化的字符串 来在可发现性抬头显示器中显示出来 当它以选择器的形式时 就会调用action 的 perform 并且需要输入 在这个例子中 只包含空格的字符串 表明了这是给空格键的 你现在会变得很兴奋 想一想在你的 app 中添加一些 在其它 app 中会令你的用户很期待的 常用键盘快捷键 比如说 如果你正着手于 一个音乐库 app 你将会添加几个 能够使它更块地与歌曲和播放列表互动的 快捷指令 比如 全选、复制和粘贴 又或者 你正着手于一个插图 app 例如 你想有些像 Command-Plus 的东西 来放大 以及 像 Command-Minus 的东西来缩小 幸运的是 许多这些常用的键盘快捷方式 你甚至不需要创建一个 UIKeyCommand 你只需要重写几个方法就行了 每一个 UIResponder 子类 都符合一个叫做 UIResponderStandardEditActions 的协议 它可以响应这里列出的任何方法 你只需要重写相关的方法就行了 你不需要创建任何 UIKeyCommand 这是一个例子 我们的 UITableViewController 子类 位于你的 UIResponder 子类中 我们只需要重写我们之前写过的 相同的两个方法 以确保它可以成为第一响应程序就行了 通常 如果你决定 在你的控制器子类中执行这个操作 那么这个操作是必须的 接着你可以重写 在前几页中提到的的任意方法 比如全选、复制、粘贴 或其他 并且都不用创建任何 UIKeyCommand 更多指令和信息 请查看 UIResponderStandardEditActions 的 说明文档 UIKeyCommand 在设计时 考虑到了 Catalyst 使得所有这些新的键命令 与 macOS 菜单栏一起工作非常轻松 关于我在之前几页提到的 UIResponderStandardEditActions 你可以免费得到它们 但是 对于自定义 UIKeyCommand UICommand 还好是 UIKeyCommand 的子类 这意味着它可以很容易地集成到 我们为 macOS Catalina 引入的 command-builder API 想要了解更多详细信息 以及如何运用 command-builder API 查看 WWDC 2019 讲座 “将 iPad apps 带到一个新的层次”
接下来我要讲的 是硬件键盘如何与表视图 和集合视图交互 如果你有一个文件列表 比如在文件 app 中 你的用户会期待 在 Mac 上常见的一些快捷指令 在他们的 iPad 上同样可以使用 比如长按 “Shift” 并轻点两个列表项目 来选择一个连续的文件列表 就应该可以使用
其次 长按 “Command” 并轻点列表内多个项目 应该可以扩展用户的选择 而不必先进入编辑模式 幸运的是 在你的 app 中 执行你的用户所期待的这个行为 非常简单 如果你已经在使用 UITableView 或是 UICollectionView 你只需要执行 shouldBeginMultipleSelection InteractionAt indexPath 并返回 ture 系统将会自动将你的表视图 置于编辑模式 或者将你的集合视图 置于多种选择模式 并基于持有的修改键 扩展用户当前选定的一组索引路径 同样地 执行 didBeginMultipleSelection InteractionAt indexPath 使你周围的用户界面适应 被自动置于编辑模式的现实 想了解多种选择 API 可以提供给你的 其它帮助 请查看 WWDC 2019 讲座 “更新你的 iOS 13 用户界面“ 现在 让我们来了解一些 iOS 14 的更新 从我们对手势识别器添加的 一些附加功能开始 从另一个例子开始 让我们看一看 Numbers 表格 Numbers 表格利用 iPad 上的 硬件键盘 来提供更先进功能的方法之一 是在通过允许用户 长按 “Shift” 键的同时 用手指或触控板调整形状大小 以此将选定形状的比例限制到其纵横比 另外 再比如 Numbers 表格允许用户 长按 “Command” 键 并通过轻点它们 来选择多个项目 这样你就可以一次移动它们 这些都是可行的 因为在 iOS 13.4 中 当我们介绍全新的妙控键盘时 我们在 UIGestureRecognizer 中 添加了一个 叫做 modifierFlags 的性能 它允许任意 app 执行此种行为 当手势识别器的状态改变 这项性能将会被赋予 用户一直按住的任何修改键 因此 如果我们要实现类似于 我们示例中 Numbers 表格所做的事情 我们只需要在弹出手势识别器回调时 查询这个性能 并根据所持的修改键执行相应的操作 更多关于事件及手势识别器的 更新信息 请查看 “处理触控板及鼠标输入” 讲座 我最后想讲的一件事 是关于 一个全新的响应原始键盘事件的 API 在应用程序中实现硬件键盘交互 可以在你的 app 的某些方面 给你的用户提供更细粒度的控制 还是用 Numbers 表格作为例子 Numbers 表格利用硬件键盘的准确性 并符合用户预期 来允许用户进行小的调整 使用箭头键创建形状或层 这要求你响应一个 key-down 事件 以开始移动对象 并响应一个 key-up 事件 以结束移动对象 这两个事件都 无法使用 UIKeyCommands 实现 只能在用户调用后激发一次 在更新的 iOS 中 我们添加了可以 响应所有从连接的硬件键盘执行的 key-up 和 key-down 事件 回到我们的朋友 响应程序链 所有这些都通过叫做 pressesBegan 和 pressesEnded 的 UIResponder 方法实现 你只需要在视图控制器的视图中 重写这两个方法 那么一旦键被按或被释放时 你就会开始得到通知 同样 使用模型视图控制器模式时 我们在像 canvas 视图控制器的东西上 重写 pressesBegan 和 pressesEnded 在 pressesBegan 中 当一个键在硬件键盘上按下时被调用 我们可以检查按键代码 看是哪个箭头键被按下了 并在我们的应用程序中执行适当的操作 在按键按下时开始连续移动形状 然后 在 pressesEnded 中 你只需执行应用程序中 停止移动形状的任何操作就行了 就是这么简单 同样地 类似于我们为手势识别器添加的功能 你也可以检查每个键事件的修饰符标记 并作出必要调整 例如 允许用户在移动项目时 长按 “Shift“ 来选择 另外 我们还将仅使用辅助按键 来通知你 有关 key-down 和 key-up 事件 最后 你接下来需要做什么 确保你的 app 可以使用你的用户所期待的 所有常见键盘快捷方式 增强你的 app 的 完全自定义键盘快捷方式 以此使你的用户更有效率 创建菜单项目 以便你的 app 在 macOS 中能被运用自如 最后 使用新的硬件键盘 API 来在你的 app 中 完成令人惊叹的键盘体验 谢谢收看 请 “喜欢”、“评论” 并 “订阅”
抱歉 我完全搞混了
-
-
0:01 - PlayerViewController
class PlayerViewController: UIViewController { override var canBecomeFirstResponder: Bool { return true } override func viewDidAppear(_ animated: Bool) { becomeFirstResponder() } override var keyCommands: [UIKeyCommand]? { return [ UIKeyCommand(title: NSLocalizedString("PLAY_PAUSE", comment: "…"), action: #selector(playPause), input: " ") ] } }
-
0:02 - SongListTableViewController
class SongListTableViewController: UITableViewController { override var canBecomeFirstResponder: Bool { return true } override func viewDidAppear(_ animated: Bool) { becomeFirstResponder() } /* UIResponderStandardEditActions */ override func selectAll(_ sender: Any?) { … } override func copy(_ sender: Any?) { … } override func paste(_ sender: Any?) { … } }
-
0:03 - UIKeyCommand
class UIKeyCommand : UICommand { ... } override func buildMenu(with builder: UIMenuBuilder) { builder.replaceChildren(ofMenu: .file) { children in return [ UIKeyCommand() ] + children } }
-
0:04 - Extending selection with keyboard
optional func tableView(_ tableView: UITableView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool optional func tableView(_ tableView: UITableView, didBeginMultipleSelectionInteractionAt indexPath: IndexPath)
-
0:05 - recognizedDragGesture
func recognizedDragGesture(_ panGesture: UIPanGestureRecognizer) { if panGesture.modifierFlags.contains(.command) { snapToGrid = true } else if panGesture.modifierFlags.contains(.shift) { constrainAspectRatio = true } ... }
-
0:06 - Responding to raw keyboard events
class UIResponder: NSObject { func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent) func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent) }
-
0:07 - CanvasViewController
class CanvasViewController: UIViewController { override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) { for press in presses { guard let key = press.key else { continue } switch key.keyCode { case .keyboardUpArrow: startMoveUp() case .keyboardDownArrow: startMoveDown() … } } } override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) { stopMoving() } }
-
0:08 - CanvasViewController modifier flags
class CanvasViewController: UIViewController { override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) { var selectWhileMoving = false for press in presses { guard let key = press.key else { continue } if key.modifierFlags.contains(.shift) { selectWhileMoving = true } switch key.keyCode { case .keyboardUpArrow: startMoveUp() } } } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。