大多数浏览器和
Developer App 均支持流媒体播放。
-
UIKit 的新功能
探索 UIKit 的最新更新和改进,以及如何构建更出色的 iPadOS、iOS 和 Mac Catalyst App。我们将介绍 UI 改进、生产效率更新、API 增强,等等。我们还将帮助您探索如何提高性能和安全性,并更好地保护隐私。
资源
- Building a desktop-class iPad app
- centerItemGroups
- UICalendarView
- UINavigationItem.ItemStyle
- UIPageControl
相关视频
WWDC22
- 利用 Swift 并发消除数据争用
- 在 SF 符号中采用可变颜色
- 将 SwiftUI 与 UIKit 搭配使用
- 构建桌面级 iPad App
- 桌面级 iPad 简介
- 采用桌面级编辑交互
- SF 符号 4 的新功能
- Swift 并发的可视化与优化
- TextKit 和文本视图的新功能
WWDC21
-
下载
欢迎收看 iOS 16 的 “What's New in UIKit” 我是 Dima 是 UIKit 团队的工程经理 UIKit 是App 开发用到的一个强大的核心框架 它已经更新 以支持 iOS 16 中的新功能
在这个视频中 我将介绍 为提升效率进行的 UI 改进 控件增强 API 的改进 我还将谈到令人振奋的 同步使用 UIKit 和 SwiftUI 的新方法
我们让在 UIKit 中开发出 精简 可发现的用户界面更容易 它有着改进过的导航栏 包含新的标题菜单 查找和替换 以及重新定义编辑交互用户界面的 剪切 复制和粘贴 你将能够增强基于文档的应用程序 我会先从仔细研究导航栏开始 它经过了更新 以支持桌面类工具栏功能
在 iOS 16 中 UIKit 引入了两种新的导航样式 以更好地支持基于文档的 App 浏览器和编辑器
浏览器风格是为使用历史记录 或文件夹结构导航的 App 如网页和文档浏览器而设计的
该编辑器主要用于 以编辑文档为中心的界面
在 iOS 16 中 你可以在 App 中 添加各种各样的栏按钮项 它们的一个子集会显示在 导航栏中心
点击菜单中的 “customize toolbar”条目 就可以通过拖拽 来重新排列弹出的项目
由此产生的新配置 在 App 启动时持续存在
例如 为了适应大小的变化 当使用另一个 App 进入并排模式时 系统会自动提供一个悬浮菜单 来访问任何不适合的项目
我们添加了一个标题菜单 它与新的导航样式一起运作 并支持一些标准功能 复制 移动 重命名 导出和打印 当要实施相应的委托方法时 这些将自动显示在菜单中 也可以在标题菜单中 添加完全自定义的条目
此外 使用 Mac Catalyst 构建的 App 无需额外的代码便可与 NSToolbar 无缝集成 充分利用了改进的导航栏
iOS 16 引入了在不同的 App 中 一致地操作文本的新方法 第一个是新的查找和替换 从概念上讲 它不同于对数据模型对象 如照片或日历事件进行操作的 更高级的 App 内搜索项目 相反 查找与替换 是专门用于处理文本的 它只需要设置一个标志 来激活如 UITextView 和 WKWebView 的内置 UIKit 视图功能
此外 它无缝地跨越了 选入该系统的多个视图 和文档工作
接下来 编辑菜单进行了重大升级 它现在因输入法不同而有所区别 在触摸交互方面 重新设计的菜单 更具互动性
当使用指针时 你会得到一个 功能更全面的快捷菜单
为了无缝提供这两种体验 我们引入了 UIEditMenuInteraction 完全替代现在已弃用的 UIMenuController
还有新的 API 可以将操作 插入到文本视图的菜单中
你可以观看 “Adopt desktop class editing interactions” 来学习新编辑菜单上的所有细节 并学习如何为自定义视图 采用查找交互
我还想说说一个可视化 UI 更新 在 iOS 16 中 侧边栏会在 滑动模式下自动显示 不需要任何额外的代码 为了实现这一点 UIKit 会代你管理一组私有视图
这些是 UIKit 中 用于提高生产力的新功能 新的可自定义导航栏 查找与替换 编辑交互 以及强大的标题菜单 我只是提到了皮毛 要了解更多 请查看课程 “Meet desktop class iPad” 以及更深入的 “Build a desktop class iPad app” 在那里 你将通过 一个示例 App 的改进 了解 iOS 16 中新的高级 UIKit 功能
现在 我将介绍我们添加的 两个新控件 谈谈对 UIPageControl 的一些增强
UIDatePicker 的内联日历样式 现在作为一个独立的全功能组件 以 UICalendarView 的形式提供 UICalendarView 支持不同类型的选择行为 如可选单个日期 也支持选择多个日期 除了可用日期范围 它还支持禁用个别日期选择
此外 你可以用装饰来注释单个日期
UICalendarView 和 UIDatePicker 之间的一个主要区别 在于 UICalendarView 将日期表示为 NSDateComponents 而不是 NSDate 与 NSDate 不同 日期组件是更好的 更正确的日期表示 而 NSDate 是时间点的表示
因为 NSDateComponents 提供了很大的灵活性 你应该能明确组件 是由哪个 NSCalendar 来表示的
注意 你不应该对当前日历的类型 做出假设 如果你需要将日历设置为公历 请明确指定公历
要像前面显示的那样 配置 Calendar 视图 首先创建 Calendar 视图 并设置其委托 要确保 Calendar 有 Gregorian NSCalendar 支持 将 calendarView 上的 Calendar 属性 设置为 Gregorian NSCalendar
接下来 要配置多日期选择 创建一个 UICalendarSelectionMultiDate 对象 并将选择对象上的选定日期属性 设置为数据模型中 显示在 Calendar 视图里的 现有日期
然后 将选择对象设置为 日历视图的选择行为
为了防止日历中单个日期的选择 执行 multidateselect: canSelectDate: method 通过日历选择委托 控制哪些日期可以被选择
无法选择的日期 将在日历视图中显示为灰色
要用装饰来注释单个日期 执行日历委托的 calendarView: decorationForDateComponents:Method
如果不要装饰 只需返回 nil 即可
对于默认的灰圆 返回默认装饰
你还可以通过自定义颜色选项 来创建图像装饰 如果你需要做到更多 可以使用 customView 装饰 并在视图提供程序中返回你的视图
请注意 自定义视图装饰不允许交互 并会被裁剪到可用空间
页面控件也得到了改进 我们为当前页面添加了 支持自定义指示器图像 这样你现在就可以根据页面 是否被选中 来选择不同的图像
你现在还可以完全自定义 页面控件的方位和方向
下面是配置垂直页控件的示例 该控件的指示器 在当前页与非当前页之间更改
我将页面控件的方向 设置为从上到下 并设置了首选指示器图像 首选当前指示器图像 这样就大功告成了
Apple 致力于保护用户隐私和安全 在 iOS 15 中 当 App 以编程方式访问粘贴板 而不使用系统提供的 Paste 接口时 将出现一个横幅 表明该粘贴板已被访问
在新的 iOS 16 中 系统行为发生了变化 现在 我们会显示 请求使用粘贴板许可的提示 而不是横幅
与用户交互的系统粘贴接口 提供了对粘贴板的隐式访问 从而避免了提示
如果你有自定义的粘贴控件 就可以用新的 UIPasteControl 替换它们 它的外观和行为 都像一个填充过的 UIButton
当粘贴板获得与控件的粘贴目标 兼容的内容时 将启用该选项
这些是新的强大的 UICalendarView 改进过的 UIPageControl 以及重视安全的 UIPasteControl 去试试吧 现在 我将向你介绍 我们所做的一些 API 改进
在 iOS 15 中 锁止器被添加到了工作表中 这能支持构建灵活 动态的 UI 在 iOS 16 中 我们增加了支持自定义锁止器 这样你就可以制作任意大小的工作表
要利用这个功能 请使用新的 “.custom” 锁止器 并在关联块中 以点为单位指定工作表的高度 你可以返回一个常量值 或最大锁止高度的百分比
如果你需要从其他 API 引用它 也可以为自己的自定义锁止器 提供一个标识符 例如禁用超越自定义锁止器的调光
请注意 从自定义块返回的值 不应该包含底部嵌入式安全区域 因此浮动和 侧附加工作表的计算方法相同
要了解更多关于有系统锁止器 和其他选项的自定义工作表 请观看视频“Customize and resize sheets in UIKit” 那个视频的示例代码也进行了更新 以展示这些新的自定义锁止器 API
UIKit 中的 SF 符号有新功能 符号支持四种呈现模式 单色 多色 分层和调色 UIKit 会默认使用单色呈现 除非符号被配置为不同的呈现模式 在 iOS 16 中 如果没有指定呈现模式 UIKit 可以使用单色以外的模式 呈现单个符号
以这些设备符号为例 在 iOS 15 及之前的版本中 如果没有指定呈现模式 这些符号将使用单色呈现
在 iOS 16 中 这些符号默认为分层呈现
通常 符号的默认呈现模式 是展示该符号的首选方式 因此在这种情况下 你应该允许默认的分层呈现 生效 不过 单色呈现可以通过新的 UIImage.SymbolConfiguration. preferringMonochrome() API 来明确请求
UIKit 增加了对可变符号的支持 它允许 App 根据从 0 到 1 的值 显示符号的变化 假设一个 App 想要用一个符号 描述当前音量级别 该 App 可以使用 speaker.3.wave.fill 符号 它已被更新 以支持变量呈现 在值为 0 时 扬声器波逐渐消失 表示最低音量水平 当该值增加到 1 时 扬声器的波形逐渐填充 表明更高的音量水平
如果一个符号支持变量呈现 那么 App 就可以请求一个 反映 0 到 1 之间值的版本的符号
使用变量符号很直白 你可以通过标准的 SF Symbols API 在 UIImage 上获得一个 常规非变量版符号
要获得带有特定变量值的该符号版本 只需添加 variableValue 参数
你甚至可以将变量呈现 与其他呈现模式 如调色 混合 以进一步设计符号的样式
许多系统符号现在支持可变呈现 并且 App 可以 更新它们的自定义符号来支持可变性
要学习如何创建自定义变量符号 记得观看“Adopt variable color in SF Symbols” 和 “What's new in SF Symbols 4” 这两个课程
我们已经更新了 UIKit 以和新的 Swift Concurrency 功能同时使用 包括使不可变类型 如 UIImage 和 UIColor 符合 Sendable 这样你就可以在 MainActor 和自定义 actor 之间发送它们 而不会收到编译器警告
例如 我们有一个叫做处理器的 自定义 actor 以及一个被绑定到 MainActor 的 叫做 ImageViewer 的视图控制器 在 sendImageForProcessing 方法中 ImageViewer 将图像发送给 处理器 actor 进行处理 使其看起来 像添加了闪光和彩虹一样漂亮 这是安全的 因为 UIImage 是不可变的 处理器必须创建新的拷贝 来添加彩虹和闪光
任何引用原始图像的代码 都不会显示这些修改 共享状态也不会发生不安全的变化
对比一下因为可变 而不可发送的 UIBezierPath
以前只能在文档中表示的东西 现在可以 由编译器进行检查 这多棒啊
要了解更多关于 Sendable 和 Swift Concurrency 的知识 请查看视频“Eliminate data races using Swift Concurrency” 和“Visualize and optimize Swift Concurrency”
iOS 16 对外部显示器 提供了新的强大支持 好消息是 你不需要更新你的 App 来利用它 除非你使用的是旧版 UIScreen API
你不能再默认你的 App 在主屏幕上 相反 你要遵从更具体的 API 比如 trait collection 和 UIScene API 来获得你需要的信息 如果你的 App 仍未使用 UIScene 现在你有了更多的理由升级 以支持多窗口
UICollectionView 和 UITableView 中的 自定大小单元格受到了重大升级 现在单元格也可以自我调整大小了 在 iOS 16 中 当可见单元格内的内容发生变化时 单元格将自动调整大小 以适应新内容
这个新行为是默认启用的 UICollectionView 和 UITableView 各有一个新的 selfSizingInvalidation 属性 让你能控制这个新功能
以下是它的运作方式
当启用 selfSizingInvalidation 时 单元格可以请求通过其包含的集合 或表视图来调整大小
如果你用了 UIListContentConfiguration 配置单元格 那么每当单元格的配置发生更改时 失效就会自动发生
对于任何其他情况 你都可以调用单元格 invalidateIntrinsicContentSize 方法 或它的 contentView 来调整单元格的大小
默认情况下 单元格会随着动画而调整大小 但是你可以用 performWithoutAnimation 中的 invalidateIntrinsicContentSize 绕过指令 从而不使用动画调整大小 UICollectionView 和 UITableView 将单元格的 大小无效智能合并为 在最佳时间执行的单个更新
如果你在单元格中使用 Auto Layout 你可以通过选择 enabledinclingconstraints 来完成一个更全面的行为 这意味着当一个单元格检测到它的 contentView 内部的任何自动布局变化时 它将自动调用 invalidateIntrinsicContentSize 这样包含的集合或表格视图 就可以在必要时调整它的大小 这使得单元格 随内容或布局更新自动调整大小 变得非常容易
UIKit 强大而灵活 你也可以利用通过 SwiftUI 来执行 UI 的可表达性 我们已经使在同一个 App 中 合并这两个框架容易了很多
在iOS 16 中 有一种全新的 使用 SwiftUI 为集合和表格视图 构建单元格的方式
这是通过一个名为 UIHostingConfiguration 的 新内容配置类型实现的 只需一行代码 你就可以在单元格中 开始编写 SwiftUI 完全不需要额外的视图 或视图控制器
下面是一个在 SwiftUI 中 使用 UIHostingConfiguration 编写的 简单的自定义单元格 构建这个单元格非常容易
这不仅是开始将 SwiftUI 集成到你的 App 中的一个很好的方式 而且 SwiftUI 的表达力意味着 前所未有的 在 UIKit 中 构建自定义单元格的强大方式 关于这个话题还有很多值得讨论 所以一定要看看视频 “Use SwiftUI with UIKit”来深入了解
有几个微小但重要的变化 你应该知道 为了防止用户被指纹识别 UIDevice.name 现在会报告模型名称 而非用户自定义的设备名称 现在使用自定义名称需要获得授权
不再支持设置 UIDevice.orientation 相反 要使用 UIViewController API 如 preferredInterfaceOrientation 来表达你界面的预期方向
接下来是什么 使用 iOS 16 SDK 编译你的 App 测试新功能 如文本编辑菜单 查找和替换 采用新的 UIKit API 来使用新的加强控件 和用于提高生产力的新功能 并尝试在你的 UIKit app 中 加入 SwiftUI 的新方式 谢谢大家
-
-
7:51 - Configuring a UICalendarView with multi-date selection
// Configuring a calendar view with multi-date selection let calendarView = UICalendarView() calendarView.delegate = self calendarView.calendar = Calendar(identifier: .gregorian) view.addSubview(calendarView) let multiDateSelection = UICalendarSelectionMultiDate(delegate: self) multiDateSelection.selectedDates = myDatabase.selectedDates() calendarView.selectionBehavior = multiDateSelection func multiDateSelection( _ selection: UICalendarSelectionMultiDate, canSelectDate dateComponents: DateComponents ) -> Bool { return myDatabase.hasAvailabilities(for: dateComponents) }
-
9:07 - Configure UICalendarView decorations.
// Configuring Decorations func calendarView( _ calendarView: UICalendarView, decorationFor dateComponents: DateComponents ) -> UICalendarView.Decoration? { switch myDatabase.eventType(on: dateComponents) { case .none: return nil case .busy: return .default() case .travel: return .image(airplaneImage, color: .systemOrange) case .party: return .customView { MyPartyEmojiLabel() } } }
-
10:16 - Setting up a vertical UIPageControl with custom indicators
// Vertical page control with custom indicators pageControl.direction = .topToBottom pageControl.preferredIndicatorImage = UIImage(systemNamed: "square") pageControl.preferredCurrentIndicatorImage = UIImage(systemNamed: "square.fill")
-
12:21 - Creating a custom sheet detent
// Create a custom detent sheet.detents = [ .large(), .custom { _ in 200.0 } ]
-
12:38 - Creating a custom sheet detent using a percentage of maximum detent height
// Create a custom detent sheet.detents = [ .large(), .custom { context in 0.3 * context.maximumDetentValue } ]
-
12:42 - Assigning identifiers to custom sheet detents
// Define a custom identifier extension UISheetPresentationController.Detent.Identifier { static let small = UISheetPresentationController.Detent.Identifier("small") } // Assign identifier to custom detent sheet.detents = [ .large(), .custom (identifier: .small) { context in 0.3 * context.maximumDetentValue } ] // Disable dimming above the custom detent sheet.largestUndimmedDetentIdentifier = .small
-
22:16 - UIHostingConfiguration example
cell.contentConfiguration = UIHostingConfiguration { VStack { Image(systemName: "wand.and.stars") .font(.title) Text("Like magic!") .font(.title2).bold() } .foregroundStyle(Color.purple) }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。