为 iPad 构建应用
Build for iPad
2020年6月23日
一句话判断
iPadOS 14 为 iPad 带来了更桌面化的体验:侧边栏导航、下拉菜单、工具栏、以及更紧凑的模态视图。如果你的 iPad App 还停留在”放大版 iPhone”的阶段,这个 Session 给你提供了完整的升级路线图。
这场 Session 讲了什么
iPadOS 14 的设计目标是为 iPad 带来更多的桌面级生产力体验,同时保留触屏操作的直观性。Session 介绍了 iPadOS 14 中四个核心的 UI 模式更新。
第一,全新的侧边栏模式(UISplitViewController 的三栏布局),支持可折叠的分组、拖拽排序和上下文菜单。第二,下拉菜单(UIMenu)替代了传统的 Action Sheet,让用户可以通过点击或触控板触发层级式菜单。第三,紧凑的日期选择器和编辑弹出框,不再占据整个屏幕。第四,工具栏(Toolbar)可以在侧边栏切换时动态调整布局。Session 通过 Apple 自家的 Files、Notes 等 App 来演示这些模式的实际应用。
值得深挖的点
侧边栏的三栏布局
iPadOS 14 推荐使用 UISplitViewController 的三栏布局(Supplementary Column)。主视图是可折叠的侧边栏,中间是列表,右边是详情。用户可以通过按钮或手势来展开/折叠侧边栏。这种布局在 Files、Notes、Music 等 Apple 自家 App 中已经全面采用。对于有导航层级结构的 App 来说,这是最推荐的布局模式。
从 Action Sheet 到 UIMenu
iPadOS 14 引入了更紧凑的上下文交互方式。传统的 Action Sheet 在 iPad 上占据太多屏幕空间。新的 UIMenu 可以作为一个下拉菜单从按钮或工具栏项触发,支持层级结构和图标。用户还可以通过触控板右键或长按来触发上下文菜单。
代码片段
配置三栏 Split View 布局
场景:为邮件类 App 创建侧边栏 + 列表 + 详情的三栏布局。
import UIKit
class MailSplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 使用三栏布局
preferredDisplayMode = .twoBesideSecondary
preferredSplitBehavior = .displace // 侧边栏展开时推开内容
// 设置侧边栏的显示模式
preferredDisplayMode = .primarySidebar // 默认显示侧边栏
// 创建三个视图控制器
let sidebarVC = MailboxSidebarViewController()
let mailListVC = MailListViewController()
let mailDetailVC = MailDetailViewController()
// 使用 NavigationController 包装
let sidebarNav = UINavigationController(rootViewController: sidebarVC)
let listNav = UINavigationController(rootViewController: mailListVC)
let detailNav = UINavigationController(rootViewController: mailDetailVC)
// 设置为三栏
setViewController([sidebarNav, listNav, detailNav])
// 侧边栏的显示/隐藏
toggleSidebarMode()
}
private func toggleSidebarMode() {
// 在侧边栏按钮点击时切换显示模式
let targetMode: UISplitViewController.DisplayMode =
displayMode == .primaryHidden ? .primaryBesideSecondary : .primaryHidden
preferredDisplayMode = targetMode
}
}
使用 UIMenu 替代 Action Sheet
场景:为工具栏按钮创建下拉菜单。
class MailToolbarViewController: UIViewController {
@IBAction func moreButtonTapped(_ sender: UIBarButtonItem) {
// 创建层级菜单
let moveMenu = UIMenu(title: "移动", image: UIImage(systemName: "folder"), options: [], children: [
UIAction(title: "收件箱", image: UIImage(systemName: "tray")) { _ in
self.moveToInbox()
},
UIAction(title: "已归档", image: UIImage(systemName: "archivebox")) { _ in
self.moveToArchive()
},
UIAction(title: "垃圾邮件", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
self.moveToSpam()
}
])
let mainMenu = UIMenu(title: "", children: [
UIAction(title: "回复", image: UIImage(systemName: "arrowshape.turn.up.left")) { _ in
self.reply()
},
UIAction(title: "转发", image: UIImage(systemName: "arrowshape.turn.up.right")) { _ in
self.forward()
},
moveMenu, // 嵌套子菜单
UIMenu.separator(), // 分隔线
UIAction(title: "标记未读", image: UIImage(systemName: "circle")) { _ in
self.markUnread()
}
])
// 作为下拉菜单显示
sender.menu = mainMenu
}
}
配置侧边栏的列表样式
场景:使用 UICollectionView 创建 macOS 风格的侧边栏。
import UIKit
class MailboxSidebarViewController: UIViewController {
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<String, MailboxItem>!
override func viewDidLoad() {
super.viewDidLoad()
setupSidebar()
}
private func setupSidebar() {
// 使用 Sidebar 列表外观
var layoutConfig = UICollectionLayoutListConfiguration(appearance: .sidebar)
// 配置滑动操作
layoutConfig.leadingSwipeActionsConfigurationProvider = { indexPath in
let action = UIContextualAction(style: .normal, title: "置顶") { _, _, completion in
completion(true)
}
return UISwipeActionsConfiguration(actions: [action])
}
let layout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
// 注册 Cell
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, MailboxItem> {
cell, indexPath, item in
var content = cell.defaultContentConfiguration()
content.text = item.name
content.image = UIImage(systemName: item.iconName)
content.secondaryText = "\(item.unreadCount)"
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource<String, MailboxItem>(
collectionView: collectionView
) { collectionView, indexPath, item in
collectionView.dequeueConfiguredReusableCell(
using: cellRegistration, for: indexPath, item: item
)
}
}
}
最佳实践
已有项目:如果你的 iPad App 使用了 UISplitViewController,升级到三栏布局。把侧边栏的 UICollectionView 列表外观切换为 .sidebar 模式。将 Action Sheet 替换为 UIMenu,特别是在工具栏和导航栏的场景下。
新项目:从产品规划阶段就采用三栏布局。这是 iPadOS 的标准导航模式,Apple 自家 App 已经全面采用。使用 UICollectionLayoutListConfiguration(appearance: .sidebar) 来创建侧边栏,它已经内置了合适的间距、字体和交互反馈。
还有什么值得关注
- iPadOS 14 的
UISplitViewController支持自动记忆用户选择的侧边栏展开/折叠状态。 - 侧边栏外观(
.sidebar)自动使用半透明材质背景,不需要手动配置。 - 搭配 Session 10093 和 10094 可以了解触控板交互的适配细节。