大多数浏览器和
Developer App 均支持流媒体播放。
-
UIKit 的新功能
探索 UIKit 的改进和更新,并了解如何构建理想的 iOS、iPadOS 和 Mac Catalyst App。我们将向你展示 UIKit 的最新功能和改进,并分享在 API 和性能等方面上的改进。
章节
- 1:23 - Key feature: Xcode previews
- 2:08 - Key feature: View controller lifecycle
- 5:09 - Key feature: Trait system enhancements
- 6:26 - Key feature: Animation symbol images
- 7:49 - Key feature: Empty states
- 9:51 - Internationalization
- 13:34 - iPad: Document support
- 13:55 - iPad: Window dragging
- 14:47 - iPad: Sidebar and Stage Manager
- 16:56 - iPad: Apple Pencil
- 19:33 - iPad: Keyboard scrolling
- 20:21 - General: Collection views
- 23:03 - General: Spring animations
- 24:03 - General: Text interactions
- 25:12 - General: Status bar
- 26:19 - General: Drag and drop
- 27:00 - General: HDR images
- 27:34 - General: Page control
- 28:42 - General: Palette menus 🎨
- 30:08 - tvOS menus
资源
相关视频
WWDC23
WWDC20
-
下载
♪ ♪
Dima:大家好 欢迎观看 “iOS 17 UIKit 的新功能” 我是 Dima 是 UIKit 团队的工程经理 作为你的 App 背后的强大框架 UIKit 已经升级 现在支持 iOS 17 的新功能 在这个视频中 我将带你了解以下内容: 新的关键功能和核心架构改进、 为不同语言设置的所有用户 构建界面时的改进、 对 iPadOS 上的 App 的改进 以及此版本中包含的许多常规改进
我们对 UIKit 进行了 重大架构改进 使其更容易构建强大的 App 并大大提高了 与 SwiftUI 的集成能力 我将介绍五个全新关键功能 它们是:Xcode 预览支持、 视图控制器生命周期的更新、 特征系统的改进、 动画符号图像 以及 App 中 表示空状态的新 API
首先 一个重大的变化是: 你可以直接在 UIKit 中 使用 Xcode 预览 要充分利用此功能 就要使用 Preview 宏 来指定预览名称 并返回一个视图控制器 我可以在视图控制器上 设置任何属性 以便使用数据配置和填充预览
你还可以直接预览 UIView 无需视图控制器 预览可帮助你可视化 UI 组件 并在代码迭代过程中提供即时反馈 当你的 App 创建完成时 Xcode 预览使你 能在各种配置和设置下 进行测试 接下来 我想介绍一项重要改进 与在外观过渡过程中 视图控制器的生命周期有关 例如在你呈现一个视图控制器时 或者在导航控制器中 推入或弹出视图时 viewIsAppearing 是个新增的视图控制器回调 在 viewWillAppear 后、 viewDidAppear 前调用 每次视图出现时 最适合使用 viewIsAppearing 当它被调用时 视图控制器和视图的特征集合 得以更新 此外 视图已被添加到视图层次中 并由其父视图进行布局 这使 viewIsAppearing 这一回调 非常适合运行依赖于尺寸等 视图初始几何属性的代码 最后 viewIsAppearing 这一新方法 可以向后部署到 iOS 13 因此 即便你的 App 在旧版 iOS 中运行也可使用该方法
这里展示了在一个典型的 视图控制器外观过渡过程中 新回调 viewIsAppearing 如何与其他关键事件配合使用 我想指出几点
首先 请留意 viewWillAppear 在视图被添加到视图层次前 以及在布局开始前 是如何被调用的 这就是为什么此时使用特征集合 或执行任何依赖于视图大小 或其他几何属性的操作为时过早
第二 请留意 viewDidAppear 如何在所有动画都已完成时 最后在另一个 CATransaction 中被调用 这意味着你在 viewDidAppear 中 所做的任何更改 直到过渡结束后才看得到 因此在过渡过程中 你作出的任何更改来不及显现 相反 viewIsAppearing 与 viewWillAppear 在相同的事务中被调用 这意味着从过渡的第一帧开始 你在这两个回调中所做的任何更改 就立即可让用户看见
最后 虽然调用时间相似 但 viewIsAppearing 与 viewWillLayoutSubviews 等布局回调之间 有个很关键的区别
布局回调在每次视图运行 layoutSubviews 时调用 在过渡过程中可能被多次调用 或者过渡结束后 视图可见的时候调用
但是 viewIsAppearing 在外观过渡过程中只会被调用一次 即使视图不需要布局也会被调用 这是为什么我喜欢 把 viewIsAppearing 看成 Goldilocks 回调: 因为它不会过早、过晚 或过于频繁地被调用 而是刚刚好 在 iOS 17 中 UIKit 中的特征系统已经升级 特征会自动通过 App 的层次结构传播数据 UITraitCollection 包含许多系统特征 例如用户界面样式、 水平和垂直尺寸分类 以及首选内容尺寸类别
现在你可以定义自定义特征 将数据添加到 UITraitCollection 这是一个将数据传输到 App 中 视图和视图控制器的全新方式
我们也添加了 新的特征覆盖 API 用于轻松修改 任何视图或视图控制器上的特征值
你也可以在特征值更改时 采用更灵活的 API 接收回调 无需在子类别中覆盖 traitCollectionDidChange
最后 你可以将 自定义 UIKit 特征 和自定义 SwiftUI 环境键桥接 以便在 UIKit 组件 和 SwiftUI 组件之间无缝传递数据
如要全面了解这些超赞新改进 请观看视频 “释放 UIKit 特征系统”
在我们的所有平台中 SF Symnols 让工具栏图标、导航栏 以及其他 UI 元素的外观保持一致 SF 符号可自动与文本标签对齐 你可以根据 App 的设计 轻松自定义字体粗细、 缩放效果和外观 在 iOS 17 中 UIKit 添加了新的符号效果 API 用于支持动画化符号 这些效果可以应用在任何 符号图像甚至自定义的符号图像上
你可以在 UIImageView 上使用新的 addSymbolEffect() 方法添加效果 这里 我添加一个弹跳的特效 这样符号就会弹跳一次 我现在添加一个颜色变化特效 与弹跳特效不同 颜色变化特效 在添加后不断显现动画 使用 removeSymbolEffect() 方法 可以终止其效果 最后 我可以使用新的 setSymbolImage() 方法 在不同符号间实现过渡的效果
关于符号效果的内容还有很多 远不止我刚刚演示的三个功能 若想进一步了解 请观看视频 “在 App 中为符号添加动画” 接下来看看已添加的一个新 API 如何让表示空状态更简单 空状态就是 App 没有 要显示的内容的时候
通常在 App 首次启动时出现 因为还没有创建任何内容 空状态也在 App 出现一些限制 例如没有网络连接的时候出现 UIContentUnavailableConfiguration 是一个对空状态的可组合描述 可添加占位符内容 例如图像或文本 在这里的例子中 情况是没有收藏的翻译要显示 为了表示这个空状态 我将配置设置为视图控制器的 contentUnavailableConfiguration 除了 .empty() 配置 也可以通过 UIKit 中的 .loading () 配置 来表示正在准备的内容 还有 你可以借助 UIHostingConfiguration API 使用 SwiftUI 视图 来表示 App 的空状态 这和将 UIHostingConfiguration 与单元格一起使用相同
更新视图控制器的不可用内容配置的 最好的地方 就是在新方法 updateContentUnavailableConfiguration (using: state) 中
这个例子使用了 .search 配置 该配置专门用于不返回结果的查询 该配置提供本地化的 主要文本和次要文本 内容包含在旁边的 搜索控制器中插入的查询
每当视图控制器中 内容可用性改变时 调用 setNeedsUpdateContentUnavailableConfiguration 来请求更新 在所有 Apple 平台上 为使用不同语言设置的用户 提供一致的优质体验 是至关重要的 为了达到一点 我们在字体和文本显示上 做出了重大改进
在这个部分 我会介绍 动态行高调整 它有助于 避免某些字体和语言中 文本的裁剪和碰撞问题 你也会了解到 经优化的断行和连字规则 以及基于地点 请求图像的新 API 首先 我们仔细看一下 字体及其度量
字体度量由好几个术语定义 基线代表的是 一条在字母或单词底部 想象出来的线 行高指的是两条基线之间的间距 x 字高线是小写字母 顶部的一条线
一些字体的升部 和降部会超出这些线 升部是字体 超出 x 字高线的部分 降部则是超出基线的部分 对于阿拉伯语、 印地语和泰语等语言 这些元素比拉丁字母 需要更多的垂直空间 这就可能导致碰撞或裁剪问题 为了在所有语言中避免 升部和降部的重叠 我们引入了动态行高调整功能 该功能确保 UILabel 等文本元素 自动调整行高 和垂直尺寸 以获得最佳阅读体验 我们还对中文、德文、 日文和韩文等语言的 断行行为进行了大幅改进
这些改进根据你使用的文本样式 应用不同的规则
在大多数情况下 只要你采用了文本样式 这些改进都会自动应用不同的规则 但如果想详细了解最佳实践 以及如何确保你的 App 在所有语言中都正常工作 请观看 “文本和文本交互的新功能” 在某些情况下 UI 中很大一部分内容 可能以不同于用户选择的语言显示 例如来自网站的内容 在这些情况下 你可以使用新的排版语言特征 来指定界面的语言 这会有助于 相应地调整行高和连字规则 UIKit 现在支持访问 特定的本地化图像变体 例如 character.textbox SF 符号 包含八个 基于地点的不同变体
默认情况下 UIKit 会根据 设备的当前语言设置 提取匹配的变体 所以 如果当前的 语言是英语 (美国) 就会显示拉丁变体
iOS 17 中的 App 可通过在图像配置中 提供 Locale 来请求特定变体 这里 我通过提供一个 带有日语地点的配置 来查找该符号的日语版本 通过这些关于 文本渲染和地点支持的改进 你的 App 可以 让所有用户都感觉更亲切
现在 我将为你介绍 为 iPad 构建 App 方面的改进
我会介绍五个方面的改进: 新窗口拖动操作、 台前调度中增强的侧边栏行为、 键盘滚动支持、 关于构建 以文档为中心的 App 的改进 以及 Apple Pencil 的 新功能和 API
在 iOS 17 中 我们通过 扩大拖动手势的开始区域 更新了台前调度窗口拖动功能
现在 在 UINavigationBar 中 任何位置拖动 都会开始移动窗口 这个手势与 App 中可能存在的 其他手势识别器兼容 例如平移或轻扫手势 如果你的 App UI 中没有 UINavigationBar 你可以采用 UIWindowSceneDragInteraction 并将其添加到任何视图中 你也可以设置与 App 中 其他平移手势的手势关系 以确保没有冲突 无需额外的设置即可 与 Mac Catalyst 一起使用 在台前调度中 列式的 UISplitViewController 包含全新优美的调整大小行为 在需要时 侧边栏会自动隐藏 并保持隐藏 直到用户请求显示 当在较窄的窗口上请求侧边栏时 UISplitViewController 会根据需要使用覆盖或位移行为
当窗口尺寸变大时 侧边栏依然以覆盖的方式显示 在较宽的窗口上 关闭再打开侧边栏时 侧边栏会以平铺的方式显示 三列分屏视图控制器的行为也相似 例如邮件中的视图控制器 这个新行为是由 使用双列或三列样式创建的 UISplitViewController 控制的 总结一下: 自动行为会尽可能平铺列 当宽度减小时 系统会根据需要隐藏侧边栏; 当你点击侧边栏按钮时 如果没有足够的平铺空间 系统会覆盖或移动 带有侧边栏的辅助列 你还可以使用 preferredDisplayMode 和 preferredSplitBehavior 在 App 中覆盖这种行为 在 iPadOS 17 中 我们改进了 对以文档为中心的 App 的支持 UIKit 提供一个新的 UIDocumentViewController 作为内容视图控制器的基类 它保证提供系统默认体验 以及许多功能 无需额外采用 例如自动配置标题菜单、 共享、拖放、快捷键等等 另外 UIDocument 现在遵循 UINavigationItemRenameDelegate 并在被设置为视图控制器导航项的 重命名代理时 提供完整的重命名体验 如要进一步了解关于 这些和其他 专注于文档管理的 App 新功能 请观看 “构建基于文档的理想 App”讲座 Apple Pencil 为 iPadOS App 添加了一个额外功能 还引入了许多新的 API
在全新 iPad Pro 和 iOS 16.4 中 我们引入了 Apple Pencil 的悬停功能 要捕捉笔的悬停 你可以使用 UIHoverGestureRecognizer z 偏移量反映了 笔离屏幕的标准化悬停距离 数值范围是从 0 到 1 你还可以捕捉笔在悬停范围内的 高度和方位角 以准确地渲染屏幕上的笔触预览
你还可以在主屏幕 和 App 的工具栏图标上悬停 如果你正在使用 UIPointerInteraction 无需额外采用其他内容 但值得注意的是 使用鼠标或触控板输入 与使用 Apple Pencil 输入时的视图交互略有不同 例如 在使用 Apple Pencil 时 系统指针等指针样式是不可见的
一定要在 你的 App 上试试悬停功能
在 iOS 17 中 PencilKit 有更强的表现力 并引入了新的墨水效果 单线笔非常适合细节绘制 可以画出宽度一致的线条 钢笔则模拟了书法的效果 下降笔画粗 上升笔画细 水彩笔可以绘制出美丽的笔触 具有很强的表现力 蜡笔是一个有趣的新增功能 在使用新的墨水效果时 请考虑向后兼容性 之前的 iOS 版本无法加载 包含新墨水效果的 PKDrawings
在数据模型类型中 如 PKDrawing、PKStroke 等 添加了一个新的 content version 属性 用于表示加载对象 所需的 PencilKit 版本 content version 为 1 代表 iOS 14 的墨水; content version 为 2 则代表 iOS 17 的新墨水
为了提供良好的用户体验 可以使用此 API 检测不兼容性 并反馈一条消息 或渲染备用图像 当无法保持向后兼容性时 可以使用新的 maximumSupportedContentVersion API 通过画布或工具选择器 限制可用的功能
为了使配备妙控键盘等硬件键盘的 iPad 变得更强大 我们添加了对键盘滚动的支持 在 iOS 17 中 可以使用 Page Up、 Page Down Home 和 End 键 来滚动 UIScrollView 你可以使用 UIScrollView 上的 新 API allowsKeyboardScrolling 来覆盖此行为 最后 我将逐一为你介绍 我们在 UIKit 的多个方面 所做的常规改进
我将为你介绍 八项综合性改进的全部内容: 集合视图的改进、 新的弹簧动画参数 以及文本交互等等
我先介绍集合视图 它在 iOS 17 中 进行了大幅优化 有许多性能改进 这些图展示了在处理大量数据项时 集合视图在 iOS 17 中有多快
在颠倒集合视图中 一万个数据项的排列顺序时 iOS 17 的性能 几乎比 iOS 16 快了一倍 在删除五千个数据项的更新操作上 iOS 17 比 iOS 16 几乎快了三倍 另外 当你执行 没有动画效果的更新操作时 集合视图的性能有更大的提升 无论是将快照 应用到可差异化数据源 还是手动执行批量更新操作 iOS 17 中集合视图的性能 都有显著的全面提升 这些改进使你的 App 有更快的响应速度 减少了 App 中的卡顿 现在 我将介绍 Compositional Layout 中一个强大的新功能 首先用一个 相当典型的布局示例来说明 这是 iPad 上全新的健康 App 其中个人收藏部分使用了 每行两个项目的组合布局 每个项目都用 NSCollectionLayoutDimension.estimated 自动调节大小 请注意 药物单元格的高度 与旁边单元格的高度不匹配 如果这一行的单元格高度都相同 看起来会好很多
在 iOS 17 中 组合布局引入了 一个全新的布局维度: uniformAcrossSiblings
这个新功能使布局中 自动调节大小的项目 可调整至与最大元素一致的大小 当你需要这种布局时 只需将 estimated 维度 替换为 uniformAcrossSiblings 请记得 使用此功能时 需要创建所有同级元素并确定尺寸 以确定最大元素的大小 因此 不要在 有大量项目的组中使用
回到健康 App 的例子 这个组里有两个不同高度的项目 我们使用 uniformAcrossSiblings 更新了布局中的所有项目 于是药物单元格 与环境音量级别单元格的高度一样 这样就得到了想要的布局效果 接下来谈谈弹簧动画 我们一直在改进一种 指定参数的新方式 这种新方式要更容易理解和使用
它只使用两个参数: 持续时间和弹跳
持续时间指的是 弹簧动画达到稳定状态需要的时间 而不是指动画完全完成所需的时间 持续时间和弹跳是两个独立的参数 弹跳从零增加 会为动画增加弹跳效果 而不会改变动画的持续时间
我们在 UIView 上添加了 一个使用这些弹簧参数的新方法 而且它们都是可选的 所以现在你甚至可以 只写“animate” 就可以得到 与系统默认值相匹配的弹簧动画
请观看“使用弹簧制作动画”讲座 深入了解这种描述弹簧的新方式
接下来 我将介绍 文本交互的新功能和 API 在 iOS 17 中 我们对 文本光标和文本选择 UI 进行了一些重大改进 包括重新设计的选择放大镜 使用文字处理器等 自定义文本视图的开发者 现在可使用 系统提供的选择 UI 视图 无需采用 UITextInteraction
UITextViewDelegate 上的新 API 使文本视图中的文本项交互 有很多可自定义项 开发者可以修改文本项 例如链接或文本附件的 主要操作或菜单
此外 你还可以 为内容标记自定义范围 实现与文本范围的交互 从而更容易地 向非链接文本添加操作或菜单
如要进一步了解有关文本光标改进 以及文本项操作和菜单的更多信息 请观看 “文本和文本交互的新功能”讲座 现在我将介绍 iOS 中 一个相当成熟的元素的更新: 状态栏 在 iOS 上 状态栏的样式 由其下方的 App 控制 默认样式会根据 App 或视图控制器的 深色、浅色两种模式自动切换 在一些用户内容中 不容易保证良好的对比度
这里的默认样式是深色的 因为 App 使用了浅色用户界面 但是其中一些用户内容是深色的
现在 在 iOS 17 中 默认样式会根据 App 的内容 不断地调整 并自动在深色和浅色样式之间切换 以保持良好的对比度 状态栏甚至可以根据需要 同时显示两种样式
由于 App 不再需要 为所有这些情况 明确指定深色或浅色 因此你可以考虑删除自定义代码 并使用默认样式 在 iOS 17 中 拖放功能变得更强大了 现在可以将支持的文件和内容 拖放到主屏幕上的图标上 并直接在相应的 App 中打开 这个功能如今自动适用于 许多基于文档的 App 你无需做出任何更改 系统使用在 App 的 Info.plist 文件中 定义的 CFBundleDocumentTypes 来确定是否支持拖放文件 在拖放时 系统使用 现有的场景代理方法打开文件 就像处理其他的 URL 一样 要使用这项功能 只需确保你的 App 定义了其支持的文档类型 UIKit 新增了 对 ISO HDR 图像的支持 使你可以通过 UIImageView 轻松显示这些图像 并使用 UIGraphicsImageRenderer 进行图像操作
此外 在使用新的 UIImageReader 加载图像时 有更多控制选项 包括将某些 HDR 图像格式 例如来自相机胶卷的图像 转换为 ISO HDR 要了解更多信息 请观看 “在 App 中支持 HDR 图像”讲座
UIPageControl 添加了新功能 用于表示页面的分数进度 如今在 App 中 经常使用页面控件 以幻灯片放映方式显示内容 这些内容可以自动根据设定的时间 或视频内容自动翻页 通过新的进度和计时器进度 API 你现在可以在 活动指示器中表示页面分数进度 更好地让用户了解 在什么时候会翻页 要设置分数进度页面控件 只需使用进度对象在 UIPageControl 上 设置新 progress 属性
UIPageControlTimerProgress 具有内置计时器 可以轻松配置每个页面的持续时间
当计时器持续时间结束时 UIPageControl 会自动切换页面
对于需跟随视频播放器或外部计时器 即具有自己的真实数据源的页面 可以使用基础类型 UIPageControlProgress 来手动更新 currentProgress 值 以跟踪内容的进度 iOS 17 和 macOS Sonoma 引入了调色板菜单
调色板是一行菜单元素 通常用于从一组项目中 进行颜色选择 这种控件样式和 iOS 上的图书 App 或 Mac 上的邮件 和访达中的控件样式类似 现在它是 UIKit 中的 一个基本控件了 要将菜单转换为调色板 只需像这样在菜单的选项中添加 .displayAsPalette
由于调色板中的元素相对较小 选择不会使用勾号来表示 不像常规菜单元素中那样 相反 UIKit 将根据提供的图像 选择合适的选择指示器 如果调色板中的所有元素 使用单色的 SF 符号 或模板图像 选定的元素将会 以 App 的色调颜色进行着色 如果元素使用 多色的 SF 符号 系统则在选定的 元素周围以色调颜色描边 如果你在菜单元素中 完全使用自定义图像 或者如果你想通过 提供自己的选择指示器 来覆盖内置行为 你可以使用 UIMenuLeaf 协议上的 新 selectedImage 属性 在该例子中 selectedImage 是在 UIAction 的初始化程序中设置的
UIKit 的菜单 API 在 iOS、 iPadOS 和 Mac Catalyst 上都可用 这使你能够使用 熟悉的 API 构建复杂的菜单 而且 从 tvOS 17 开始 所有上述 API 也可在 Apple TV 上使用 并具有全新的外观 和原生 tvOS 行为 很好 我们已经讲了很多内容 UIKit 真的新增了一系列功能 变得更强大了
接下来可以做什么呢? 使用 iOS 17 SDK 编译你的 App 在项目中使用 UIKit 新功能 并充分利用 Xcode 预览功能 同时确保你的用户界面 能够灵活适应 非拉丁语言的不同文本度量 希望你喜欢对这些主题的简要概述 如果你想要更深入地了解 可以查看相关视频 谢谢观看 ♪ ♪
-
-
1:31 - Using Xcode previews with view controllers
class LibraryViewController: UIViewController { // ... } #Preview("Library") { let controller = LibraryViewController() controller.displayCuratedContent = true return controller }
-
1:48 - Using Xcode previews with views
class SlideshowView: UIView { // ... } #Preview("Memories") { let view = SlideshowView() view.title = "Memories" view.subtitle = "Highlights from the past year" view.images = ... return view }
-
8:19 - Setting up UIContentUnavailableConfiguration
var config = UIContentUnavailableConfiguration.empty() config.image = UIImage(systemName: "star.fill") config.text = "No Favorites" config.secondaryText = "Your favorite translations will appear here." viewController.contentUnavailableConfiguration = config
-
8:56 - Using UIContentUnavailableConfiguration with SwiftUI
let config = UIHostingConfiguration { VStack { ProgressView(value: progress) Text("Downloading file...") .foregroundStyle(.secondary) } } viewController.contentUnavailableConfiguration = config
-
9:21 - Using UIContentUnavailableConfiguration for search results
override func updateContentUnavailableConfiguration( using state: UIContentUnavailableConfigurationState ) { var config: UIContentUnavailableConfiguration? if searchResults.isEmpty { config = .search() } contentUnavailableConfiguration = config } // Update search results for query searchResults = backingStore.results(for: query) setNeedsUpdateContentUnavailableConfiguration()
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。