为 iPad 而设计
Designed for iPad
2020年6月23日
一句话判断
iPad 不是”大号 iPhone”——如果你的 iPad 应用只是 iPhone 版的等比放大,你浪费了这个平台最有价值的特性:多窗口、触控笔、键盘和宽屏布局。
这场 Session 讲了什么
这场 Session 从设计角度重新审视了 iPad 应用的体验设计。iPadOS 14 在多窗口管理、Scribble(Apple Pencil 手写输入)、Sidebar 导航和 Compact Layout 方面做了大量改进。Session 强调了”iPad 独特体验”的核心:大屏幕不是用来看更多内容的,而是用来做更复杂的事情的。
Sidebar 导航是 iPadOS 14 最重要的 UI 变化之一。Apple 推荐所有 iPad 应用采用”Sidebar + Content”的两栏布局,替代传统的底部 Tab Bar。Sidebar 可以折叠为 compact 模式(只显示图标),也可以展开显示完整的标签和分组。这个设计充分利用了 iPad 的宽屏空间——导航在左侧,内容在右侧,一眼就能看到完整的信息层级。
Scribble 是 iPadOS 14 的新特性,用户可以在任何文本框中直接用 Apple Pencil 手写,系统实时将笔迹转换为文本。这对开发者来说几乎是透明的——你的应用不需要做任何适配就能支持 Scribble。但 Session 建议在自定义文本控件中测试 Scribble 的兼容性,特别是那些有自定义输入逻辑的控件。
Session 还讨论了键盘快捷键的最佳实践。iPad 的键盘用户(外接键盘或 Magic Keyboard)期望用 Cmd+N 新建、Cmd+W 关闭窗口、Cmd+, 打开设置。你的应用应该支持这些标准快捷键。
值得深挖的点
Sidebar 的三种显示模式
iPadOS 的 Sidebar 有三种模式:expanded(完整显示图标和文字)、compact(只显示图标)和 hidden(完全隐藏,通过按钮切换)。你的布局需要自适应这三种状态——expanded 时内容区域变窄,compact 时内容区域变宽。SwiftUI 的 NavigationSplitView 自动处理了这个适配,但用 UIKit 实现需要手动监听 sidebar 的状态变化。
多窗口的设计考量
iPadOS 支持同一应用的多个窗口。比如邮件应用可以同时打开两封邮件并排对比。Session 讨论了多窗口场景下的状态管理:每个窗口应该有独立的导航栈,但共享数据源。用户在窗口 A 中删除了一封邮件,窗口 B 应该立即反映这个变化。
代码片段
import SwiftUI
// iPad Sidebar + Content 布局
struct iPadAppView: View {
@State private var selectedItem: NavigationItem?
@State private var columnVisibility: NavigationSplitViewVisibility = .all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
// Sidebar(左侧导航)
List(NavigationItem.allItems, selection: $selectedItem) { item in
NavigationLink(value: item) {
Label(item.title, systemImage: item.icon)
}
}
.navigationTitle("我的应用")
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
} detail: {
// Content(右侧内容区)
if let item = selectedItem {
DetailView(item: item)
} else {
Text("请选择一个项目")
.foregroundColor(.secondary)
}
}
}
}
struct NavigationItem: Identifiable, Hashable {
let id: String
let title: String
let icon: String
static let allItems: [NavigationItem] = [
NavigationItem(id: "inbox", title: "收件箱", icon: "tray"),
NavigationItem(id: "sent", title: "已发送", icon: "paperplane"),
NavigationItem(id: "drafts", title: "草稿", icon: "doc"),
NavigationItem(id: "archive", title: "归档", icon: "archivebox"),
NavigationItem(id: "trash", title: "已删除", icon: "trash"),
]
}
// 支持键盘快捷键
import SwiftUI
struct KeyboardShortcutView: View {
@State private var showNewDocument = false
@State private var searchText = ""
var body: some View {
ContentView()
.searchable(text: $searchText) // Cmd+F 自动聚焦搜索栏
.keyboardShortcut("n", modifiers: .command) {
// Cmd+N: 新建文档
showNewDocument = true
}
.keyboardShortcut("w", modifiers: .command) {
// Cmd+W: 关闭当前窗口
// 由系统自动处理
}
.keyboardShortcut(",", modifiers: .command) {
// Cmd+,: 打开设置
openSettings()
}
.sheet(isPresented: $showNewDocument) {
NewDocumentView()
}
}
func openSettings() {
// 导航到设置页面
}
}
// 自定义 Scribble 支持的文本输入
import SwiftUI
import PencilKit
struct CustomTextField: UIViewRepresentable {
@Binding var text: String
var placeholder: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField()
textField.placeholder = placeholder
textField.delegate = context.coordinator
// Scribble 自动支持,无需额外配置
// 但可以在 delegate 中拦截输入做自定义处理
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
}
最佳实践
- iPad 应用采用 Sidebar 导航而非底部 Tab Bar,充分利用宽屏空间
- 支持多窗口时确保每个窗口有独立的导航栈,共享数据通过单一数据源管理
- 为所有主要操作提供键盘快捷键,遵循 Apple 的标准快捷键约定
- 测试 Scribble 在自定义文本控件中的表现,特别是有输入验证的表单
- 在 iPad 和 iPad mini 两种屏幕尺寸上测试布局,确保 compact/expanded 状态都正常
还有什么值得关注
- iPadOS 14 的 Sidebar 可以通过设置
navigationSplitViewColumnWidth自定义宽度 - Compact sidebar 模式下点击图标会自动展开 sidebar,用户不需要手动切换
- Apple Pencil 的双击手势(切换工具)可以在应用中自定义,通过
UIPencilInteraction实现