大多数浏览器和
Developer App 均支持流媒体播放。
-
面向 iOS 13 对您的 UI 进行现代化改造
iOS 13 新增了功能强大的多任务处理和效率技术,并为所有 app 带来了崭新的外观和体验。熟悉新要求,让 app 为即将推出的 iOS 版本做好准备。探索搜索栏的改进,以及全新的 UI 显示方式。了解如何采用与选择相关的新手势,如何在所有硬件上使用轻瞄和突显,以及如何面向 iOS 13 更新您 app 的外观。
资源
相关视频
WWDC22
WWDC21
WWDC20
WWDC19
-
下载
(针对iOS 13 现代化你的UI)
大家好 这是针对iOS 13 现代化你的UI演讲
我是David Duncan 稍后我的同事 Russell、Kyle、
James和Mohammed 会上台来一起演讲
在这场演讲中 我们要讲六件事 准备好app的灵活性UI
我们针对栏和呈现 所做的改进 app中搜索的新功能 让app变得 更加多产的新手势 一些你之前一直没能做到的示例 最后我们要回顾 本周稍早些时候 发布的新情境菜单API
那么让我们谈谈灵活性UI
那么具有灵活性的第一步… 是当用户打开app时 他们首先会看到什么
自iOS 8以来 故事板是表达启动UI的优选方式
但自iOS诞生之日起 我们还支持另一种可替换的方法
就是启动图像 启动图像要求你为每一个 你所支持的屏幕尺寸 指定一张图像 并在产生新的屏幕尺寸时进行修订
那样灵活性很低
因此明年春季 2020年四月 链接了iOS 13 SDK 的app 必须提供一个启动故事板 以便被App Store接受 你再也不用只提交启动图像了 因此 如果你还没有采用启动故事板 现在正是时候
那会引导你进入下一个变更 你可能已经听说了
就是在过去… 如果我们引入 拥有新屏幕尺寸的新硬件 你的app将会是宽屏幕格式 嗯 我们也不再打算那样做了 因此 如果你的app采用了 iOS 13 SDK 那么它将总是 以屏幕的原生全屏分辨率显示 因此 我们期待 任何采用iOS 13的app 都使用合适的API 来确保正确的布局 在任意尺寸的屏幕上
对于那些创建iPad app 的开发人员来说 这也适用于分屏多任务 因此 我们期待绝大多数app 除非你需要提供非常拟真的体验 都支持分屏多任务功能 你的app可以以任意尺寸 紧邻其它app显示 可能是用户所选择的其它app
如果你不确定…
如果你可以支持全部这些 重调尺寸模式 以及其它一切功能 你可能会想尝试另外一件事 尤其是当你有iPad app时 那就是专门为Mac创建 通过我们在macOS Catalina中 添加的新技术支持 并且你直接就能在办公桌上实现 要确保重调尺寸之后的任意尺寸 看起来都很漂亮
那么在此之前 要采用启动故事板 用户即将看到启动UI 当用户首次启动你的app时 要确保app的布局 支持任意尺寸的屏幕 无论是最小的iPhone 还是最大的iPad
最后 确保你的iPad app 同样也支持分屏多任务功能 因为你必须在 2020年四月之前实现
然后让我们再谈谈栏
那么…
如果你在安装测试版之后 看一下手机 你可以看到现在的栏是如何显示的 当你持续向上滚动到顶部时 我们会退出背景 当我们向下滚动时 我们把它带回来了 既流畅又透明
类似地 在iPad上 如果你有分割视图控制器 我们分别为两个方向 都执行这样的效果 无论细节是否支持大标题
并且它们会分别进行响应 因此显示哪个背景 取决于滚动方向
现在你可能会问 要如何采用这个? 如何确保 它能很好地嵌入我的app中?
嗯 采用方法很简单 链接iOS 13 你会免费获得它
但如何让它在你的app中 完美地发挥作用 可能需要花点儿时间 因此我们引入了新外观自定义API 来帮助你实现
那么让我们来看一下 在新外观API中 自定义导航栏是什么样子 (新栏外观) 那么我们要做的第一件事
就是创建对象 它实际上表示外观 UINavigationBarAppearance 是UIBarAppearance 的子类 它压缩了 UINavigationBar的 全部自定义选项 在这种情况下 我们实际上要让导航栏 使用一种不透明的颜色 因此我们要使用默认值 它是由configureWith OpaqueBackground提供的
那会让导航栏的背景遵守 明亮和暗黑模式 并显示一种恰当的不透明颜色
在这个特例中 我们还想改变标签颜色 因此我们可以设置 titleTextAttributes 和largeTitleTextAttributes 我们要给它们设定一个 我们即将使用的自定义颜色 另一种动态颜色 正因为如此 才能保证 在明亮和暗黑模式中看起来都很棒
最后我们要把它应用到 导航栏的标准外观上
那么什么是 standardAppearance? 嗯 让我们来看看
导航栏 当它是自己的尺寸时 没有大标题 它是标准尺寸 这就是standardAppearance 所表达的东西 此外 如果你不指定其它外观配置 我们会对其它两个配置 使用默认配置 我们稍后再谈
那么如果你使用 较小屏幕的iPhone横屏模式 你会得到 compactAppearance 这就是它所表达的东西 它的数量
之前我们在iOS 13中看到过 导航栏把它的背景变成了透明的 当你从滚动视图的顶部向下拉动时 那就是 scrollEdgeAppearance 无论何时 当导航栏与滚动视图相关联时 这在app中很常见 如果你处于滚动视图的顶部 那么我们将使用 scrollEdgeAppearance替换标准外观 默认是使用一个透明背景 这就是为什么 你会得到无缝外观的原因 无缝外观是我们在iOS 13中 新添加的功能
此外 你还可以自定义 栏按钮项的外观 并自定义buttonAppearance 获取plain项的外观 以及自定义doneButtonAppearance 获取done项的外观
现在我们可以暂停一下 你得到了导航栏 它是自定义导航栏 很棒
但我们决定把它应用到 Toolbar和TabBar 以便你可以用非常相似的方法 自定义所有栏 每一个类都能使用它们自己的 UIBarAppearance子类 来实现它们自己的自定义功能 ToolbarAppearance 实际上就是一个 与navigationBarAppearance 相关的属性子集 因此再进一步也没有多大意思 但TabBarAppearance 有点不一样 那是因为TabBar也有点不一样
那么对于TabBar 针对三个布局外观 拥有附加的自定义选项 stackedLayoutAppearance、 你将在iPad上看到的 inlineAppearance 以及你将在小屏幕手机上看到的 compactInlineAppearance
那么你可以把它们放在一起
并获得全部栏的新自定义外观
但还有另一件事
如果你看一下 新Reminders app 当你导航到一个列表时 它的标题颜色会发生改变 以匹配列表颜色
它的实现方式是 对每个导航项都使用 不同的外观自定义 那就允许你根据 要放到navigationBar 上的导航项指定外观
导航项也与导航相关联 或与视图控制器相关联 因此 放到导航控制器上 将会自动使用那个
那么它看起来是什么样呢?
嗯… 导航项拥有 与navigationBar 相同的属性 因此通常要做的事就是 从navigationBar中 获取标准外观 并复制 以便与那个外观相分离
并做一切你想要做的变更 如果你希望它是透明的 你可以使用配置透明 你可以修改栏按钮项的外观等等
然后你再把它分配给导航项 一旦完成 无论何时当视图控制器 和导航栏项处于当前时 我们都将使用那个外观而不是 navigationBar的基本外观 从而确保你可以自定义你的 navigationBar 无论应用了哪种视图控制器
为此我要邀请Russell上台来 为大家讲讲呈现
(呈现)
谢谢David
大家好 我是Russell 我也刚接触iOS 13 对于呈现我们有一个标准设计 我今天要跟大家分享一下 我感到非常激动
比如说如果我处于通讯录app中 并且我轻触了加号 来添加一个新联系人 我们有一个新的呈现样式 看起来是这样的 而不是之前的全屏呈现 你可以看到根视图控制器的视图 并没有按比例缩小 也没有从视图等级中移除
这个设计的分层 给你的用户提供了一种情境 关于他们处于app中的哪个位置 并且圆形顶部外观的作用是一个信号 表示可以交互式地清除这些呈现 在系统的任何地方
那么…谢谢
那么这个新的呈现样式是什么呢? 这些呈现叫做Sheets Sheets也不是什么新东西 这些呈现 只是当前 UIModalPresentationStylepageSheet 以及它兄弟 formSheet的新设计
之前 这些样式会采用全屏呈现 在宽度压缩的环境中 现在它们只会保留sheet 以及它们自己的特别布局 和压缩宽度 与常规宽度的布局不一样
那么让我们通过实际操作看一些例子
在手机和竖屏模式中 你会获得你刚看到的外观 但在手机的横屏模式中 你获得一个与之前一样的全屏布局
但我们不能遗忘iPad 在这点上我们重新思考了 Sheets 页面Sheets悬浮 在屏幕中央的堆栈中 并且如果有呈现多重Sheet 它们会在检查控制器顶部形成堆栈
特别是这个新尺寸要遵从可阅读宽度 因此对于文本内容来说很完美 并且因为可阅读宽度 会随着用户当前所选择的动态类型 尺寸的变更而变更 这些页面Sheet的尺寸也会改变 像这样或甚至是像这样 或者它们会呈现堆叠式外观 如果它们的优选宽度 比可用宽度更宽的话
要在你的app中获得这个新外观 你都需要做哪些操作呢? 嗯 你要做的很少 因为你已经做了许多工作 让这种转换变得尽可能简单了
默认的UIViewController ModalPresentationStyle 变成了一种新样式 叫做Automatic
Automatic 是一种动态呈现样式 在呈现时使用 为了说明它的行为 让我们一起来看几个例子
那么在这里 我有一个自定义视图控制器 它将呈现 UIImagePickerController 显示用户的相册 请注意那儿并没有设置 任何模型呈现样式
在iOS 12中使用的同样的代码 会全屏呈现图片选择器 现在将以Sheet形式呈现 而你不需要修改任何代码
另一方面 如果我配置UIImagePickerController 以呈现相机模式 这段代码将在iOS 13中 全屏呈现相机 就像它在iOS 12中那样 这是自动的 解决不同的样式 根据系统提供视图控制器的配置方式 因此你不需要修改任何代码
现在如何呈现 我们自己的视图控制器呢? 如果我简单地初始化并呈现 UIViewController的自定义子类 它将以Sheet形式呈现 换句话说 在默认情况下 Automatic 决定pageSheet
这很棒 因为它对于 绝大多数呈现来说样式很棒
再一次 不需要修改任何代码
但如果是 最后这个例子的情况会怎样? 如果你有一个自定义视图控制器 应该全屏呈现 比如你自己的自定义相机 或其它沉浸式体验 你可能会发现当你创建这部分代码时 你的沉浸式体验就会转变为 一个Sheet 但不要担心 要修复这个问题你所要做的就是 把这个视图控制器的 modalPresentationStyle 明确地设置为全屏
通常来说 保留属性的默认值就可以 只需要指定一个确切值 当你有意偏离默认行为时
那么Popovers呢? Popover现在总会适应工作表 因此 如果你想要一个 常规宽度的Popover 和压缩宽度的Sheet 你所要做的就是 把模态呈现样式设置为 Popover 然后就完成了 然后你将完全获得那种行为
现在… 要支持下拉清除需要做哪些操作呢?
一般来说 什么也不用做 如果你把某个东西 以Sheet形式呈现 你就可以免费获得下拉功能 我们将在你所呈现的整个视图中 加入一个手势识别器 因此在任意非交互性区域执行的下拉 都将触发Sheet的下拉
如用户在包含scrollView 的任意区域中从顶部以上执行下拉 也会下拉sheet 并且这也是免费的
然而 有时候下拉sheet 可能会不太合适
比如 如果我们呈现了与这个 一样的Sheet并输入了一些数据 那么就不应该允许下拉Sheet 因为不清楚用户 是否要丢弃或保存他们的修改 并且如果用户尝试下拉 Sheet应该和橡皮筋一样 并呈现一个 action sheet 显示用户可以进行的各种操作 从而摆脱这种情境
因此要创建这种体验 我们有两个新API 第一个是模态和呈现 是pUIViewController上的 一个属性 当你在所呈现的视图控制器上 把它设为真时 它将使Sheet处于模态状态 它不能被清除
并且你将获得橡皮筋效果 就像你刚才看到的那样 这个属性取代了现有的 isModal和Popover属性 防止Sheets和 Popovers都被清除
第二个是一个新 UIAdaptivePresentationController DelegateMethod 叫做 presentationControllerDidAttemptToDismiss 因此如果你在相关的呈现控制器上 设置委托 UIKit将调用这个方法 当用户在模态状态下执行下拉时 那时你可以呈现 action sheet
在这里你可以看到 这些API之间的关系 只有当isModalInPresentation为真时 才会调用DidAttemptToDismiss 并且用户下拉和释放的目的是清除 有一点儿强迫或暴力 我们把它叫做Modal Flow 并且我有一个示例项目可以演示 到底如何实施 一个像这样的例子 但请看一下描述中的链接 了解如何下载它
但我们还有更多 我们还有几个委托回调函数 PresentationControllerShouldDismiss 用于从委托中阻止清除 WillDismiss用于获取 视图控制器的一个转换协调器 你可以用它设置周边的动画、 交互变更通知和动画完成块 以及DidDismiss 用于清除状态 因为它只有当用户 实际下拉Sheet 并完成转换时才会被调用一次
这三种回调函数取代了拥有 相似命名的UI Popover presentationControllerDelegate 回调函数 这些API既可在Sheets中 又可在Popovers中调用
请记住 如用户重复拉动Sheet 而不是下拉 委托会多次收到… Should和WillDismiss 在调用DidDismiss之前 如果能收到DidDismiss
现在让我们暂时转到分享扩展
当你用iOS 13 SDK 创建分享扩展时 就像这里的邮箱一样 它将成为Sheets 并且也会实现下拉清除
那么在扩展的主视图控制器上 就像你在Info P List中 所指定的主视图控制器一样 一定要设置 isModalInPresentation 一旦用户开始输入数据 并且如果你让主视图控制器 遵从UIAdaptivePresentation ControllerDelegate 并实施 DidAttemptToDismiss 我们将调用那个方法 当用户在这种情况下执行下拉时 请注意 我们不会调用 任何其它委托方法
并且你可以在将来的种子中 获得这个行为
接下来 我想让你思考一些东西 第一个与UIViewController 外观回调函数有关 尤其是 呈现视图控制器 在全屏呈现与sheet呈现时 所接收的外观回调函数之间的区别
全屏呈现时 呈现视图控制器的视图 被从视图等级中移除 结果是它会收到 viewWillDisappear 当呈现转换开始时 然后收到viewDidDisappear 当呈现转换结束时 类似地 在清除转换过程中 当它的视图移回视图等级中时 它会收到 viewWill和DidAppear
但对于Sheet呈现 呈现视图控制器的视图 不会从视图等级中移除 因此它的视图 或视图控制器 不会收到任何外观回调函数 因此 如果你的这些回调函数中有代码 你需要在清除Sheet时执行 你应该了解一下我们刚讲过的 呈现控制器的Will 和DidDismiss方法
第二 我希望你们都考虑一下 我们插入了一些私有视图 在UIWindow之间的视图等级 及其rootViewController视图中
这个变更应该不会影响你 我们只是不希望你太吃惊 当你在视图调试器中 看到这些视图时 UIWindow之间的关系 UIWindow与其 根视图控制器的视图之间的关系 是UIKit的一个实施细节 因为UIWindow有责任 管理这个视图 并把它添加到视图等级中
一般来说 app没有视图等级结构的所有权 这个结构很容易被修改 不需要任何通知 因此一定要确保你写代码的方式 不会假定私有视图等级
(更新你的APP) 因此在你的app中 使用Sheet呈现 你可以在绝大多数UI中使用它们 极少有例外
当下拉请求用户的意图时 实施Modal Flow 请记住 有一个示例项目完全阐明了 具体如何实现… 在演讲的文档中
谢谢大家 现在我要把舞台交给Kyle 他会和大家谈谈搜索
讲得很好
谢谢Russell
大家好 我是Kyle 我的工作是做UIKit… (搜索) 我要和大家分享一下iOS 13中 关于搜索的新功能
这并不是新搜索 这是当前的搜索… Mail app中的搜索界面 它使用的是UIKit 特别是UIViewController的子类 UISearchController
我们所有用户都很熟悉它
在你的app中也可用 它由许多部分组成
最大的一部分是 UISearchBar 你可以在这里看到 在屏幕顶部
搜索栏有很多组件 包括取消按钮 以及我们叫做范围栏的东西 就是在搜索字段下方的按钮行
现在你可能注意到了范围栏 在iOS 13中更新了视觉外观
但现在我们允许app 隐藏搜索栏的元素 即使它由UISearchController 进行管理 因此如果你的app 不需要范围栏或取消按钮 但你希望它们可用 也许取决于UI状态 你可以通过UISearchController 上的新属性直接进行控制
同时… 在UISearchBar上把 SearchTextField作为公共属性进行暴露 意思是自定义非常简单
那么要自定义 SearchController的外观
请在UISearchController上 把这些属性设为假 并在UISearchBar上 使用现有属性 从而控制取消按钮 和范围栏是否可见
使用searchTextField属性 以引用 UISearchTextField实例 并修改文本字段上 你想要修改的所有属性 它是UITextField的子类 你可以在那儿使用所有的样式属性
UI搜索控制器行为也扩展到了外观 和清除搜索 因此标准行为… 是当你通过轻触它的搜索字段 而激活搜索栏时
它会升到屏幕顶部 但之前屏幕上的可见内容 仍保持可见
当你输入时 在这种情况下 手机app 会显示与你的局部搜索项 相匹配的结果
这是通过你的app提供的 UIViewController实施的 它叫做搜索结果控制器
并不是每个app都像这样 比如 在Mail app中 如果你轻触搜索字段 它会提供一份推荐搜索列表
它仍然是UISearchController的 搜索结果控制器 我们在iOS 13中 也增加了这个功能
只需要在搜索控制器上 把showsSearchResultsController 属性设为真 然后你就可以管理自动化行为了 自动显示搜索结果控制器属性
在搜索中还有另一个大功能
在Mail和Photos 以及系统上的其它app中 这些推荐搜索 结果… 是一个token 是对更复杂的 搜索查询的可视化陈述
你可以在你的app中使用这个功能 在UISearchTextField的 任意实例上 通过新 UISearchTokenAPI 并且这些token支持 复制、粘贴和拖放 这与我们在所有app上 所使用的实施一样
比如Photos用它提供所保存的 或所预测的针对人、 地点和对象的搜索
在SearchResultsController中 轻触任意一条 Photos把输入转为token 甚至是部分输入也可以
(Token和文本) 这是UITextField的子类 Token会与文本相互作用 事实上 它们总是优先于文本
比如 如果我把token 放到搜索字段中 即使我的插入点位于搜索字段末端 Token也会出现在开端
正如你在这里所看到的 token现在已被选中
我可以扩展选择 使其既包含token 又包含一些文本
(创建Token) 创建token非常简单
首先获取所选中文本的范围 以便了解你要把哪些文本 转换为token
创建一个 UISearchToken对象
并在SearchTextField上 调用这个方法 用token替换 那个范围的文本部分
你的app可以完全控制 token的插入 和移除 因此你可以赋予它 你所想要的任何意义
UITextField换成了一个 叫做UITextInput的协议
如果你正在执行程序性选择 了解一下UITextInput 非常重要 尤其是范围和位置
在常规的文本字段中 每个字符都被分配了一个 UITextPosition
并且这些位置 与两个非常著名的位置相关 文档的开端和末端 就是搜索字段的内容
你可以用这些位置来创建 UITextRanges 比如 程序性地选择 字段内容的一部分
因为token是可选择的 它们也会获得 UITextPositions
但搜索字段的文本长度… 现在与从文档开端 到最后一个字符的位置 之间的距离不一样了
如果这对你有影响 比如说 程序性地选择文本的一部分 UISearchTextField导出 这个新属性textualRange
textualRange的开端 是字段中的 第一个nontoken字符 并且它的末端是文档的末端 这些与文本属性中的字符索引相匹配
因此为了在你的app中 利用全部这些新功能 请了解一下 UISearchController上 的新属性和新自定义选项
使用UISearchTextField 无论是在UISearchBar内 或任何可以使用 UITextField的地方 并对它进行自定义 通过UITextField上 所有可用的自定义选项
采用UISearchToken 来表达复杂的查询 既简明又可编辑 它支持复制、粘贴和拖放
通过这个你可以实现许多高级技巧 我们很快会在本场演讲的网页上 添加一个示例项目 阐述如何有效地使用token
现在我要把舞台交给James 他会跟大家谈谈手势
谢谢Kyle 大家好 我是James McGaran 我今天要在这里跟大家分享 我们在iOS 13中添加的新手势 主要是选择、组织 以及一些常见的编辑快捷方式 (手势)
那么这就是我今天要讲的全部内容 你每天能听到的最棒的消息是 又有许多行为是自动实现的了 以及哪些东西可以免费使用 但我在这里要讲一些不一样的内容 以及你需要如何去做 从而充分利用这些新功能 在你的app内 那么让我们从与自定义文本视图中的 文本选择手势 相关的新功能开始讲
那么正如你所知道的 目前有许多很棒的方式 可以使用手势在iOS上选择文本 你可以轻触并按住 那会立即开始突出内容 这是iOS 13中的新功能 你可以长按来获取选择循环 并四处移动插入点 并且你可以三次轻触某一段内容 然后会立即选中整段内容
因此这些手势在本地文本小工具中 用起来得心应手 比如UITextView 和UITextField 你已经拥有这些了
但可能会有一些情况 当你需要超出TextView 和TextField的 力所能及的范围时 有些人需要在app中实施 高度自定义的文本绘制
那么这里以书为例 它使用了完全自定义的文本视图 来控制边缘、字符间距等
因此 目前为了获得这样的选择行为 在自定义文本视图中 你必须向app中手动添加 全部系统文本选择手势 只是为了拥有 与原生文本小工具同样的功能
许多人还不得不针对选择 实施自己的UI 比如选择长方形 蓝色的选择长方形 或选择控点 只是为了提供这种行为
因此我要很高兴地宣布 在iOS 13中 通过UIInteraction的 一种新类型来更简单地实现 它叫做 UITextInteraction
那么如果你不熟悉 UIInteractions 你可以把它看做是一种压缩方式 一个行为和手势的集合 与UIKit小工具相关 想想拖放互动 跟那个类似
它只是三行代码 用于向app中 添加所有系统测试选择手势 你的用户们已经熟悉那些手势了
我们提供的是一组手势 针对可编辑和不可编辑的文本交互
并且你可以使用 UITextInputProtocol 获取更精细的控制 在选择UI之上 比如我之前提到过的矩形和控点
那么这是 如何在你的自定义文本视图中 使用 UITextInteraction 那么正如我所说过的 只需要三行代码就能实现 不包含评论
你使用UITextInteraction 4 创建交互 并告诉我们你是否想添加 适用于可编辑或不可编辑的 文本字段的手势
然后把文本输入属性分配给视图 实施 UITextInputProtocol 我们把这个独立出来 万一你想 在容器视图中应用手势的话 比如滚动视图 但你希望所有文本选择行为 都能由某些内含视图进行处理 比如绘制文本的那个视图
最后只需要向视图中添加交互即可 通过添加交互
(表和集合中的多选手势) 我们将 请跟我一起—
请跟我一起来到舞台的这一侧 我们谈一下TableViews 和CollectionViews中的 多选手势
那么一直以来我们在 UICollectionView 和UITableView中 都支持多选模式
类似Notes这样的app 有一个选择按钮 位于右上角 用户可以轻触它进入多选模式 然后分别选择每一个注释 一个接一个 并把它们集合在一起 然后通过拖放 或底部的那些操作按钮来组织它们
嗯 在iOS 13中 我要很高兴地宣布 我们引入了一种全新的方式 可以快速选择连续的一批项 在集合视图和表视图中 那么让我在这个巨型iPad上 给你演示一下 那么现在用户可以立即进入 多选模式 只需要把两根手指 放在某个表或集合视图上的任意位置 并平移即可 立即开始选择
谢谢 非常棒 那么在这里你可以看到用两根手指 在文件中的列表视图中向下滑动 将立即进入编辑模式 并开始选择网格
更酷的是这在 UICollectionView 流程布局中的网格项来说同样适用 因此你的用户可以在网格项之间平移 并同时选择一批项 这对于拖放来说简直是梦想成真
更不用说如果你的用户 拥有附加的硬件键盘了 他们还能按住Shift 或Command键 以轻触其它项 和在macOS上的性能一样
谢谢
特别是你的iPad app 可以在Mac上运行 你的表视图就更如鱼得水了
那么这些很棒的新行为 目前都是可选的 原因就是因为你的app 可能需要适应 有一个不争的事实 就是你的用户打算进入多选模式 比如你可能希望修改选择或编辑按钮 变成取消或完成 你可能想显示操作按钮 在屏幕底部 通过你的用户所选择的内容 或你可能要禁用某些UI 比如本例中的添加不按钮
因此为了解决这个问题 我们添加了一些新API 帮助你适应这些新行为 非常简单 只需要实施两个委托方法 并且在表视图和集合视图上 拥有基本相同的版本
就是这些 第一个要实施的是 是否在索引路径中开始多选交互 或者你可以返回真 如果你允许手势开始的话 这里我们在这里提供了索引路径… 如果你想阻止在表视图上 不可选择的部分开始选择 在那种情况下 你只需要返回假即可
要实施的第二个方法是 是否在索引路径上 开始多选交互 你可以调整周围的UI 考虑到TableView 会自动进入多选模式 就像我们刚才在上一张幻灯片中 所讲的那样
那么继续 我想谈的最后一件事是 简要谈谈我们针对某些使用新手势的 常见的编辑任务所进行的一些改进
那么在iOS 13中 我们引入了一组标准手势 使执行某些编辑任务变得更简单 比如使用三根手指 用户可以滑动并返回到撤销
然后反向滑动到恢复
缩合三根手指可以复制…
然后捏合三根手指可以粘贴
那么我们向系统中引入了 这组标准手势 因此你就不需要担心 对这些常见的编辑命令实施UI了 它在整个系统中都是统一的 因此你的用户可以在你的app中 立即发现这些手势 并且他们会立即熟悉起来 这对于绘画app来说非常棒 因为你不需要显示 任何浮动的面板或工具栏 来实现这一行为 最棒的是它完全免费 如果你已经拥有撤销管理器 或NS撤销管理器的话
那么在这里我呼吁大家在app中 尝试这些新手势 如果有机会的话 要确保它们用起来很棒
但以防万一 我知道有些人很紧张 因此为了防止它们与你app内 可能存在的其它三指手势相冲突 我们通过一些新API 提供了一个安全舱 只是一个简单的属性 你需要覆盖 在UIResponder上 它叫做 EditingInteractionConfiguration 你可以返回无 如果你想添加这些手势的话
那么这就是我今天要讲的要点 最后要在你的自定义文本小工具中 提供全系统的标准文本选择手势 改变用户在你的app中 组织信息的方式 使用多选手势 我真的希望你们能采用它
最后请允许你的用户 停止摇晃他们的iPad 并控制撤销堆栈 通过一组标准手势
是的 的确很痛苦
谢谢大家 现在我要把舞台 交给Mohammed 他会跟大家谈谈菜单 (菜单) 好的 谢谢James
大家好 我是Mohammed 我非常激动 我要跟大家谈谈 我们在iOS 13中 引入的一些强大的新API 可以让你呈现流动性的交互菜单 并带有丰富的预览
第一个API是 UIContextMenuInteraction
UIContextMenuInteraction 是一个UIInteraction 可以让你呈现带有丰富预览 和复杂等级的菜单 这些等级可以拥有嵌套的子菜单 和内嵌节段 我们稍后再解释
由中心操作呈现的菜单高度自适应 意思是它会根据它所呈现的情境 选择呈现 在这里我们看到 在竖屏的iPhone上 预览和操作 像是一个垂直地堆叠在另一个之上
在横屏的iPhone上 预览和操作是一个挨一个 目的是为了更好地利用可用空间
并且在iPad上 它重新进行了自我配置 根据可用空间 以及预览和操作列表的尺寸
由于这是一个跨平台API 如果你的app在Mac上运行 它会变成一种 熟悉的macOS情境菜单
交互提供了一种一致的体验… 通过呈现菜单 在整个iOS中使用同样的手势
因此用户会期待这个手势 能在系统中的任何地方唤出菜单
手势将适应设备的性能 因此 在支持3D触摸的手机上 我们将使用3D触摸迅速唤出菜单 并提供一些很好的反馈
在不支持3D触摸的手机上 我们将使用触觉触摸 我们将保留那种很棒的反馈 无论何时当菜单弹出时
在其它iOS设备上 我们将使用长按 并且在Mac上 将会是用户的第二个点击设置 因此 右击或命令点击… 或两指轻触
交互与其它系统行为自动整合 比如拖放 因此如果你已经在app中 采用了UIDragInteraction 并且选择采用 UIContextMenuInteraction
用户可以在任意点转换为拖拽
因此在这里我们看到 只要达到拖拽的初始阈值 你就可以移动手指 把图片拖拽到文件app中
然而 如果你再等一会儿 直到菜单呈现出来 你仍然可以流畅地转换到拖拽模式 而不需要把手指从屏幕上移开
因此用户就会拥有这种 流畅的连续性体验
今天要讲的API的第二部分 是UIMenu和UIAction
UIMenu和 UIAction是一个… 等级菜单构建系统 允许我们定义并描述菜单等级 就是我们想要显示的菜单
UIMenus是可编辑的 它们就像积木一样 我们可以把它们组合在一起 放到不同的配置中 用于描述不同的菜单等级
这里有个简单的例子 我创建了一个拥有两个操作的菜单 通过创建UIMenu 并把它传给 UIAction 的子集实现 一个分享操作和一个删除操作
如果我想向菜单中添加更多功能 通过比如说添加子菜单 我所需要做的就是 创建另一个UIMenu 给它一些描述性标题 让它显示在等级中的前一个层级 并给它传递相应的子集 那么在这里我已经选择 包含复制和重复操作
因此当我们呈现它时 菜单看起来就像这样 顶部有一个分享操作 中间有子菜单的编辑操作 底部有删除操作
当用户轻触编辑时 会呈现我们的子菜单 然后填充我们的复制和重复操作
在你的app中采用交互 非常简单直接
如果你已经在app中 采用了其它UIInteractions 比如UIDragInteraction 或我们今年引入的某些 TextInteractions 你一定会非常熟悉这种模式
我们需要做的第一件事 就是创建UIContextMenuInteraction 用某个对象作为它的委托 那么比如说 这是我们的视图控制器
然后我们需要把它附加到某个视图上 通过UIView的 addInteraction方法
一旦这样做了 我们就需要遵守 交互的委托协议
协议有一个必需方法 当交互即将开始时调用
然后就交给app吧 要么返回一个配置 开始交互 要么返回空 表明当前位置 没有任何可以呈现的菜单
配置对象是 我们要如何描述我们的菜单
它有一个标识符 标识符是可选的 你可以用于识别… 交互 在它的整个周期中 通过你可能获得的各种 委托回调函数
它还有previewProvider 和actionProvider闭包 当即将呈现菜单时会调用它们 这会降低我们要在实际创建菜单 和预览过程中 所需要付出的潜在的昂贵的代价 除非真的需要它们
那么在我们刚才看过的示例中 菜单没有那个巨大的丰富的预览 它只有一些操作 因此我们可以主要关注 如何在委托方法的实施中 创建actionProvider
那么当调用 actionProvider时
它有一个推荐操作列表 是系统传给它的
可能既有UIMenus 又有UIActions 可能是一个构造完整的等级 是从系统中选出来的 这些可能是你在响应链中定义的东西 使用iOS 13中 新引入的UI命令API 或由其它系统组件所提供的东西
那么我们在这里做了一个 完全自定义的菜单 让我们把推荐操作放在旁边
首先我们要创建我们的编辑菜单 我们只需要创建一个UIMenu 标题是Edit 并且我们要给它传递 我们希望它拥有的两个子集 一个标题是Copy的 UIAction 以及一个标题是Duplicate 的UIAction
然后我们要定义我们的根菜单
通常来说 根目录有没有标题没有意义 因此我们可以跳过 然而如果你真心希望 给它传递一个标题 它将在操作列表上方作为页眉显示
在这里我们把三个子集传给它 一个分享操作 我们刚刚创建的编辑按钮 最后是一个 拥有毁灭性样式的删除操作 从而让用户了解 这个操作会导致毁灭性后果
最后我们创建了一个 带有某些标识符的配置 并把我们的操作提供器传给它
就是这样 这就是要使用 UIContextMenuInteraction 创建和显示菜单所要做的所有操作
但还要再花点儿时间
我们可以利用交互委托 所提供的某些动画自定义API 来创建一些非常棒、高度抛光的动画 那真的能向我们的用户们 表达我们的意思
那么在这个例子中 我用了我们刚才用过的同一个菜单 并且我用了源呈现自定义API 从而在网格的图标中显示菜单 而不是在整个网格中 并且我甚至自定义了背景颜色 甚至为预览做了一个很漂亮的圆形
这些自定义API是 在UITargetedPreview上创建的 这是在iOS 13中 引入的新API 现在如果你已经采用了 UIDragInteraction 和UIDropInteraction 并且你在app中创建了一些 自定义拖放预览 那么你很可能会觉得很熟悉这个
我们实质上是把 UITargetedDragPreview通用化 使其成为一个更通用的API 可以在其它交互中使用
UITargetedDragPreview现在是 UITargetedPreview的子类 因此如果你已经拥有了 有意义的拖拽预览 那对你的菜单来说就有意义 因为会从同一个项中触发它们 然后你可以重新使用那段代码 而不需要做任何额外的工作
为了让你在app中 更简单地采用这个 为了让你在某些最常见的情况中 更简单地唤出菜单 我们还针对UICollectionView 和UITableView 引入了一些便利的API
从app中唤出菜单 从你的app所运行的全部平台上的 表视图中唤出菜单 你所需要做的全部工作就是 在它的委托上实施一个提炼函数 在这里你会再一次返回一个配置 如果你有要显示的菜单的话 或返回空 表示没有要显示的东西
那么除此之外 这些便利的API 给你提供了一些默认的抛光动画 从表或集合视图网格中呈现菜单 然后在遣散时再返回给它们 但是我们还提供同样的自定义呈现 和遣散钩子 因此你可以创建你自己的自定义外观 和遣散动画
现在你很可能正在思考说 这听起来有点儿像预览和跳转 嗯…我们也注意到了
然而 因为这个新API 提供一个更大的功能集 并且可以在多个平台上使用 我们在iOS 13中忽略了 UIViewController预览 因此请你们替换预览和跳转的实施 通过UIContextMenuInteraction 并为用户提供一种连续性体验…
在所有设备上
你可能还想考虑 替换所有长按驱动的菜单 通过这个新交互 从而利用新的功能集
并且如果你当前有菜单 与拖拽同时显示 这是一个很棒的流动性方案 拥有协调一致的手势 和完全整合的体验 你的用户一定会期待 在iOS 13中使用
好的 那么现在你已经了解了 这么多新知识 你应该动手把你的app准备好 在iOS 13中使用 确保它们为未来做好了准备 通过把它们变得有灵活性 利用新的栏外观和呈现API 给你的app一个抛光的现代化外观 用户们一定会非常期待
着手创建你们一直以来 都想创建的搜索体验 使用很棒的新搜索API 并为你的app做一些很棒的功能 通过新手势和情境菜单
如果你对这些话题有任何疑问 或有任何与UIKit相关的疑问 请参加我们明天的讨论会 要获取关于演讲的附加信息 请查看演讲网页 谢谢大家的参与 祝大家在会议期间 度过一段愉快的时光
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。