ipados-design-guidelines
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseiPadOS Design Guidelines
iPadOS 设计指南
Comprehensive rules for building iPad-native apps following Apple's Human Interface Guidelines. iPad is not a big iPhone -- it demands adaptive layouts, multitasking support, pointer interactions, keyboard shortcuts, and inter-app drag and drop. These rules extend iOS patterns for the larger, more capable canvas.
遵循Apple人机界面指南构建iPad原生应用的综合规则。iPad不是大号iPhone——它需要自适应布局、多任务支持、指针交互、键盘快捷键以及应用间拖放功能。这些规则针对更大、功能更强的画布扩展了iOS设计模式。
1. Responsive Layout (CRITICAL)
1. 响应式布局(关键)
1.1 Use Adaptive Size Classes
1.1 使用自适应尺寸类
iPad presents two horizontal size classes: regular (full screen, large splits) and compact (Slide Over, narrow splits). Design for both. Never hardcode dimensions.
swift
struct AdaptiveView: View {
@Environment(\.horizontalSizeClass) var sizeClass
var body: some View {
if sizeClass == .regular {
TwoColumnLayout()
} else {
StackedLayout()
}
}
}iPad提供两种水平尺寸类:regular(全屏、大分屏)和compact(Slide Over、窄分屏)。为这两种尺寸类进行设计,切勿硬编码尺寸。
swift
struct AdaptiveView: View {
@Environment(\.horizontalSizeClass) var sizeClass
var body: some View {
if sizeClass == .regular {
TwoColumnLayout()
} else {
StackedLayout()
}
}
}1.2 Don't Scale Up iPhone UI
1.2 不要直接放大iPhone界面
iPad layouts must be purpose-built. Stretching an iPhone layout across a 13" display wastes space and feels wrong. Use multi-column layouts, master-detail patterns, and increased information density in regular width.
iPad布局必须专门设计。将iPhone界面拉伸到13英寸显示屏上会浪费空间,体验不佳。在regular宽度下使用多列布局、主从模式,并提升信息密度。
1.3 Support All iPad Screen Sizes
1.3 支持所有iPad屏幕尺寸
Design for the full range: iPad Mini (8.3"), iPad (10.9"), iPad Air (11"/13"), and iPad Pro (11"/13"). Use flexible layouts that redistribute content rather than simply scaling.
为全系列iPad设计:iPad Mini(8.3英寸)、iPad(10.9英寸)、iPad Air(11英寸/13英寸)以及iPad Pro(11英寸/13英寸)。使用灵活布局重新分配内容,而非简单缩放。
1.4 Column-Based Layouts for Regular Width
1.4 Regular宽度下使用基于列的布局
In regular width, organize content into columns. Two-column is the most common (sidebar + detail). Three-column works for deep hierarchies (sidebar + list + detail). Avoid single-column full-width layouts on large screens.
swift
struct ThreeColumnLayout: View {
var body: some View {
NavigationSplitView {
SidebarView()
} content: {
ContentListView()
} detail: {
DetailView()
}
}
}在regular宽度下,将内容组织成列。双列布局最为常见(侧边栏+详情)。三列布局适用于深层层级结构(侧边栏+列表+详情)。避免在大屏幕上使用单列全屏布局。
swift
struct ThreeColumnLayout: View {
var body: some View {
NavigationSplitView {
SidebarView()
} content: {
ContentListView()
} detail: {
DetailView()
}
}
}1.5 Respect Safe Areas
1.5 尊重安全区域
iPad safe areas differ from iPhone. Older iPads have no home indicator. iPads in landscape have different insets than portrait. Always use and never hardcode padding for notches or indicators.
safeAreaInsetiPad的安全区域与iPhone不同。旧款iPad没有主屏幕指示器。横屏状态下的iPad与竖屏状态下的内边距不同。始终使用,切勿为刘海或指示器硬编码内边距。
safeAreaInset1.6 Support Both Orientations
1.6 支持横竖屏两种方向
iPad apps must work well in both portrait and landscape. Landscape is the dominant orientation for productivity. Portrait is common for reading. Adapt column counts and layout density to orientation.
iPad应用必须在横竖屏状态下都能正常工作。横屏是生产力场景的主要方向,竖屏则常用于阅读。根据屏幕方向调整列数和布局密度。
2. Multitasking (CRITICAL)
2. 多任务处理(关键)
2.1 Support Split View
2.1 支持Split View
Your app must function correctly at 1/3, 1/2, and 2/3 screen widths in Split View. At 1/3 width, your app receives compact horizontal size class. Content must remain usable at every split ratio.
您的应用必须在Split View的1/3、1/2和2/3屏幕宽度下正常运行。在1/3宽度下,应用会收到compact水平尺寸类。内容在所有分屏比例下都必须可用。
2.2 Support Slide Over
2.2 支持Slide Over
Slide Over presents your app as a compact-width overlay on the right edge. It behaves like an iPhone-width app. Ensure all functionality remains accessible in this narrow mode.
Slide Over会在屏幕右侧以紧凑宽度的浮层形式展示您的应用,其表现类似iPhone宽度的应用。确保所有功能在这种窄模式下仍可访问。
2.3 Handle Stage Manager
2.3 适配Stage Manager
Stage Manager allows freely resizable windows and multiple windows simultaneously. Your app must:
- Resize fluidly to arbitrary dimensions
- Support multiple scenes (windows) showing different content
- Not assume any fixed size or aspect ratio
swift
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
// Support multiple windows
WindowGroup("Detail", for: Item.ID.self) { $itemId in
DetailView(itemId: itemId)
}
}
}Stage Manager支持自由调整窗口大小和同时显示多个窗口。您的应用必须:
- 流畅调整至任意尺寸
- 支持显示不同内容的多个场景(窗口)
- 不依赖任何固定尺寸或宽高比
swift
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
// 支持多个窗口
WindowGroup("Detail", for: Item.ID.self) { $itemId in
DetailView(itemId: itemId)
}
}
}2.4 Never Assume Full Screen
2.4 切勿假设应用始终全屏显示
The app may launch directly into Split View or Stage Manager. Do not depend on full-screen dimensions during setup, onboarding, or any flow. Test your app at every possible size.
应用可能直接启动到Split View或Stage Manager模式。在设置、引导流程或任何环节中,都不要依赖全屏尺寸。在所有可能的尺寸下测试您的应用。
2.5 Handle Size Transitions Gracefully
2.5 流畅处理尺寸转换
When the user resizes via multitasking, animate layout changes smoothly. Preserve scroll position, selection state, and user context across size transitions. Never reload content on resize.
当用户通过多任务调整大小时,平滑地为布局变化添加动画效果。在尺寸转换过程中保留滚动位置、选择状态和用户上下文。切勿在调整大小时重新加载内容。
2.6 Support Multiple Scenes
2.6 支持多个场景
Use / SwiftUI to let users open multiple instances of your app showing different content. Each scene is independent. Support for state restoration.
UISceneWindowGroupNSUserActivity使用 / SwiftUI 让用户打开应用的多个实例,显示不同内容。每个场景都是独立的。支持进行状态恢复。
UISceneWindowGroupNSUserActivity3. Navigation (HIGH)
3. 导航(重要)
3.1 Sidebar for Primary Navigation
3.1 使用侧边栏作为主导航
In regular width, replace the iPhone tab bar with a sidebar. The sidebar provides more room for navigation items, supports sections, and feels native on iPad.
swift
struct AppNavigation: View {
@State private var selection: NavigationItem? = .inbox
var body: some View {
NavigationSplitView {
List(selection: $selection) {
Section("Main") {
Label("Inbox", systemImage: "tray")
.tag(NavigationItem.inbox)
Label("Drafts", systemImage: "doc")
.tag(NavigationItem.drafts)
Label("Sent", systemImage: "paperplane")
.tag(NavigationItem.sent)
}
Section("Labels") {
// Dynamic sections
}
}
.navigationTitle("Mail")
} detail: {
DetailView(for: selection)
}
}
}在regular宽度下,用侧边栏替代iPhone的标签栏。侧边栏可为导航项提供更多空间,支持分组,在iPad上更具原生感。
swift
struct AppNavigation: View {
@State private var selection: NavigationItem? = .inbox
var body: some View {
NavigationSplitView {
List(selection: $selection) {
Section("Main") {
Label("Inbox", systemImage: "tray")
.tag(NavigationItem.inbox)
Label("Drafts", systemImage: "doc")
.tag(NavigationItem.drafts)
Label("Sent", systemImage: "paperplane")
.tag(NavigationItem.sent)
}
Section("Labels") {
// 动态分组
}
}
.navigationTitle("Mail")
} detail: {
DetailView(for: selection)
}
}
}3.2 Automatic Tab-to-Sidebar Conversion
3.2 自动将标签栏转换为侧边栏
SwiftUI with style automatically converts to a sidebar in regular width. Use this for seamless iPhone-to-iPad adaptation.
TabView.sidebarAdaptableswift
TabView {
Tab("Home", systemImage: "house") { HomeView() }
Tab("Search", systemImage: "magnifyingglass") { SearchView() }
Tab("Profile", systemImage: "person") { ProfileView() }
}
.tabViewStyle(.sidebarAdaptable)带有样式的SwiftUI 会在regular宽度下自动转换为侧边栏。使用此样式实现iPhone到iPad的无缝适配。
.sidebarAdaptableTabViewswift
TabView {
Tab("Home", systemImage: "house") { HomeView() }
Tab("Search", systemImage: "magnifyingglass") { SearchView() }
Tab("Profile", systemImage: "person") { ProfileView() }
}
.tabViewStyle(.sidebarAdaptable)3.3 Three-Column Layout for Complex Hierarchies
3.3 复杂层级结构使用三列布局
Use with three columns when your information architecture has three levels: category > list > detail. Examples: mail (accounts > messages > message), file managers, settings.
NavigationSplitView当信息架构包含三个层级(分类>列表>详情)时,使用带有三列的。例如:邮件应用(账户>消息>邮件详情)、文件管理器、设置。
NavigationSplitView3.4 Toolbar at Top
3.4 工具栏位于顶部
On iPad, toolbars live at the top of the screen in the navigation bar area, not at the bottom like iPhone. Place contextual actions in with appropriate placement.
.toolbarswift
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
Button("Compose", systemImage: "square.and.pencil") { }
}
ToolbarItemGroup(placement: .secondaryAction) {
Button("Archive", systemImage: "archivebox") { }
Button("Delete", systemImage: "trash") { }
}
}在iPad上,工具栏位于屏幕顶部的导航栏区域,而非像iPhone那样位于底部。将上下文操作放在中,并选择合适的位置。
.toolbarswift
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
Button("Compose", systemImage: "square.and.pencil") { }
}
ToolbarItemGroup(placement: .secondaryAction) {
Button("Archive", systemImage: "archivebox") { }
Button("Delete", systemImage: "trash") { }
}
}3.5 Detail View Should Never Be Empty
3.5 详情视图切勿为空
When no item is selected in a list/sidebar, show a meaningful empty state in the detail area. Use a placeholder with icon and instruction text, not a blank screen.
当列表/侧边栏中没有选中项时,在详情区域显示有意义的空状态。使用带有图标和说明文字的占位符,而非空白屏幕。
4. Pointer & Trackpad (HIGH)
4. 指针与触控板(重要)
4.1 Add Hover Effects to Interactive Elements
4.1 为交互元素添加悬停效果
All tappable elements should respond to pointer hover. The system provides automatic hover effects for standard controls. For custom views, use .
.hoverEffect()swift
Button("Action") { }
.hoverEffect(.highlight) // Subtle highlight on hover
// Custom hover effect
MyCustomView()
.hoverEffect(.lift) // Lifts and adds shadow所有可点击元素都应响应指针悬停。系统会为标准控件自动提供悬停效果。对于自定义视图,使用。
.hoverEffect()swift
Button("Action") { }
.hoverEffect(.highlight) // 悬停时显示细微高亮
// 自定义悬停效果
MyCustomView()
.hoverEffect(.lift) // 抬起视图并添加阴影4.2 Pointer Magnetism on Buttons
4.2 按钮的指针磁吸效果
The pointer should snap to (be attracted toward) button bounds. Standard UIKit/SwiftUI buttons get this automatically. For custom hit targets, ensure the pointer region matches the tappable area using .
.contentShape()指针应吸附到按钮边界。标准UIKit/SwiftUI按钮会自动具备此功能。对于自定义点击目标,使用确保指针区域与可点击区域匹配。
.contentShape()4.3 Support Right-Click Context Menus
4.3 支持右键上下文菜单
Right-click (secondary click) should present context menus. Use which automatically supports both long-press (touch) and right-click (pointer).
.contextMenuswift
Text(item.title)
.contextMenu {
Button("Copy", systemImage: "doc.on.doc") { }
Button("Share", systemImage: "square.and.arrow.up") { }
Divider()
Button("Delete", systemImage: "trash", role: .destructive) { }
}右键点击(次级点击)应弹出上下文菜单。使用,它会自动支持长按(触摸)和右键点击(指针)两种操作。
.contextMenuswift
Text(item.title)
.contextMenu {
Button("Copy", systemImage: "doc.on.doc") { }
Button("Share", systemImage: "square.and.arrow.up") { }
Divider()
Button("Delete", systemImage: "trash", role: .destructive) { }
}4.4 Trackpad Scroll Behaviors
4.4 触控板滚动行为
Support two-finger scrolling with momentum. Pinch to zoom where appropriate. Respect scroll direction preferences. For custom scroll views, ensure trackpad gestures feel natural alongside touch gestures.
支持双指滚动并带有动量效果。在合适的场景支持捏合缩放。尊重滚动方向偏好。对于自定义滚动视图,确保触控板手势与触摸手势同样自然。
4.5 Customize Cursor for Content Areas
4.5 根据内容区域自定义光标
Change cursor appearance based on context. Text areas show I-beam. Links show pointer hand. Resize handles show resize cursors. Draggable items show grab cursor.
根据上下文改变光标外观。文本区域显示I型光标,链接显示指针手型,调整手柄显示调整光标,可拖拽项显示抓取光标。
4.6 Pointer-Driven Drag and Drop
4.6 指针驱动的拖放
Pointer users expect click-and-drag for rearranging, selecting, and moving content. Combine with multi-select via Shift-click and Cmd-click.
指针用户期望通过点击拖拽来重新排列、选择和移动内容。结合Shift点击和Cmd点击实现多选。
5. Keyboard (HIGH)
5. 键盘(重要)
5.1 Cmd+Key Shortcuts for All Major Actions
5.1 为所有主要操作添加Cmd+按键快捷键
Every primary action must have a keyboard shortcut. Standard shortcuts are mandatory:
| Shortcut | Action |
|---|---|
| Cmd+N | New item |
| Cmd+F | Find/Search |
| Cmd+S | Save |
| Cmd+Z | Undo |
| Cmd+Shift+Z | Redo |
| Cmd+C/V/X | Copy/Paste/Cut |
| Cmd+A | Select all |
| Cmd+P | |
| Cmd+W | Close window/tab |
| Cmd+, | Settings/Preferences |
| Delete | Delete selected item |
swift
Button("New Document") { createDocument() }
.keyboardShortcut("n", modifiers: .command)每个主要操作都必须有键盘快捷键。标准快捷键是强制要求的:
| 快捷键 | 操作 |
|---|---|
| Cmd+N | 新建项目 |
| Cmd+F | 查找/搜索 |
| Cmd+S | 保存 |
| Cmd+Z | 撤销 |
| Cmd+Shift+Z | 重做 |
| Cmd+C/V/X | 复制/粘贴/剪切 |
| Cmd+A | 全选 |
| Cmd+P | 打印 |
| Cmd+W | 关闭窗口/标签页 |
| Cmd+, | 设置/偏好设置 |
| Delete | 删除选中项 |
swift
Button("New Document") { createDocument() }
.keyboardShortcut("n", modifiers: .command)5.2 Discoverability via Cmd-Hold Overlay
5.2 通过长按Cmd键显示快捷键列表
When the user holds the Cmd key, iPadOS shows a shortcut overlay. Register all shortcuts using so they appear in this overlay. Group related shortcuts logically.
.keyboardShortcut()当用户长按Cmd键时,iPadOS会显示快捷键覆盖层。使用注册所有快捷键,使其出现在该覆盖层中。按逻辑对相关快捷键进行分组。
.keyboardShortcut()5.3 Tab Key Navigation Between Fields
5.3 使用Tab键在输入框间导航
Support Tab to move forward and Shift+Tab to move backward between form fields and focusable elements. Use and to manage keyboard focus order.
.focusable()@FocusStateswift
struct FormView: View {
@FocusState private var focusedField: Field?
var body: some View {
Form {
TextField("Name", text: $name)
.focused($focusedField, equals: .name)
TextField("Email", text: $email)
.focused($focusedField, equals: .email)
TextField("Phone", text: $phone)
.focused($focusedField, equals: .phone)
}
}
}支持使用Tab键向前导航,Shift+Tab键向后导航,在表单输入框和可聚焦元素间切换。使用和管理键盘焦点顺序。
.focusable()@FocusStateswift
struct FormView: View {
@FocusState private var focusedField: Field?
var body: some View {
Form {
TextField("Name", text: $name)
.focused($focusedField, equals: .name)
TextField("Email", text: $email)
.focused($focusedField, equals: .email)
TextField("Phone", text: $phone)
.focused($focusedField, equals: .phone)
}
}
}5.4 Never Override System Shortcuts
5.4 切勿覆盖系统快捷键
Do not claim shortcuts reserved by the system: Cmd+H (Home), Cmd+Tab (App Switcher), Cmd+Space (Spotlight), Globe key combinations. These will not work and create confusion.
不要占用系统预留的快捷键:Cmd+H(返回主屏幕)、Cmd+Tab(应用切换器)、Cmd+Space(Spotlight)、地球键组合键。这些快捷键无法生效,还会让期望系统默认行为的用户感到困惑。
5.5 Detect Hardware Keyboard
5.5 检测外接键盘
Adapt UI when a hardware keyboard is connected. Hide the on-screen keyboard shortcut bar. Show keyboard-optimized controls. Use or track keyboard visibility to detect state.
GCKeyboard当连接外接键盘时,调整UI。隐藏屏幕上的快捷键栏,显示针对键盘优化的控件。使用或跟踪键盘可见性来检测状态。
GCKeyboard5.6 Arrow Key Navigation
5.6 方向键导航
Support arrow keys for navigating lists, grids, and collections. Combine with Shift for multi-selection. This is essential for productivity-focused apps.
支持使用方向键导航列表、网格和集合。结合Shift键实现多选。这对于生产力类应用至关重要。
6. Apple Pencil (MEDIUM)
6. Apple Pencil(中等重要)
6.1 Support Scribble
6.1 支持Scribble功能
iPadOS converts handwriting to text in any standard text field automatically. Do not disable Scribble. For custom text input, adopt . Test that Scribble works in all text entry points.
UIScribbleInteractioniPadOS会自动将手写内容转换为标准输入框中的文本。不要禁用Scribble功能。对于自定义文本输入,采用。测试所有文本输入点的Scribble功能是否正常工作。
UIScribbleInteraction6.2 Double-Tap Tool Switching
6.2 双击切换工具
Apple Pencil 2 and later supports double-tap to switch tools (e.g., pen to eraser). If your app has drawing tools, implement the delegate to handle double-tap.
UIPencilInteractionApple Pencil 2及后续型号支持双击切换工具(例如从画笔切换到橡皮擦)。如果您的应用包含绘图工具,实现委托来处理双击操作。
UIPencilInteraction6.3 Pressure and Tilt for Drawing
6.3 绘图时支持压力和倾斜感应
For drawing apps, respond to (pressure) and / (tilt) from pencil touch events. Use these for variable line width, opacity, or shading.
forcealtitudeAngleazimuthAngle对于绘图应用,响应来自Pencil触摸事件的(压力)和/(倾斜)参数。使用这些参数实现可变线条宽度、透明度或阴影效果。
forcealtitudeAngleazimuthAngle6.4 Hover Detection (M2+ Pencil)
6.4 悬停检测(M2及以上型号Pencil)
Apple Pencil with hover (M2 iPad Pro and later) provides position data before the pencil touches the screen. Use this for preview effects, tool size indicators, and enhanced precision.
swift
// UIKit hover support
override func pencilHoverChanged(_ hover: UIHoverGestureRecognizer) {
let location = hover.location(in: canvas)
showBrushPreview(at: location)
}支持悬停功能的Apple Pencil(M2 iPad Pro及后续型号)会在Pencil接触屏幕前提供位置数据。使用此功能实现预览效果、工具尺寸指示器和更高的精度。
swift
// UIKit悬停支持
override func pencilHoverChanged(_ hover: UIHoverGestureRecognizer) {
let location = hover.location(in: canvas)
showBrushPreview(at: location)
}6.5 PencilKit Integration
6.5 集成PencilKit
For note-taking and annotation, use from PencilKit. It provides a full drawing experience with tool picker, undo, and ink recognition out of the box.
PKCanvasViewswift
import PencilKit
struct DrawingView: UIViewRepresentable {
@Binding var canvasView: PKCanvasView
func makeUIView(context: Context) -> PKCanvasView {
canvasView.tool = PKInkingTool(.pen, color: .black, width: 5)
canvasView.drawingPolicy = .anyInput
return canvasView
}
}对于笔记和标注应用,使用PencilKit中的。它提供完整的绘图体验,包括工具选择器、撤销和墨水识别功能,开箱即用。
PKCanvasViewswift
import PencilKit
struct DrawingView: UIViewRepresentable {
@Binding var canvasView: PKCanvasView
func makeUIView(context: Context) -> PKCanvasView {
canvasView.tool = PKInkingTool(.pen, color: .black, width: 5)
canvasView.drawingPolicy = .anyInput
return canvasView
}
}7. Drag and Drop (HIGH)
7. 拖放(重要)
7.1 Inter-App Drag and Drop is Expected
7.1 应用间拖放是基本要求
iPad users expect to drag content between apps. Support dragging content out (as a source) and dropping content in (as a destination). This is a core iPad interaction.
swift
// As drag source
Text(item.title)
.draggable(item.title)
// As drop destination
DropTarget()
.dropDestination(for: String.self) { items, location in
handleDrop(items)
return true
}iPad用户期望能够在应用间拖拽内容。支持将内容拖出(作为源)和拖入(作为目标)。这是iPad的核心交互方式之一。
swift
// 作为拖拽源
Text(item.title)
.draggable(item.title)
// 作为拖拽目标
DropTarget()
.dropDestination(for: String.self) { items, location in
handleDrop(items)
return true
}7.2 Multi-Item Drag
7.2 多项目拖拽
Users can pick up one item, then tap additional items to add them to the drag. Support multi-item drag by providing multiple items. Show a badge count on the drag preview.
NSItemProvider用户可以拾取一个项目,然后点击其他项目将其添加到拖拽操作中。通过提供多个项目支持多项目拖拽。在拖拽预览上显示数量标记。
NSItemProvider7.3 Spring-Loaded Interactions
7.3 弹簧加载交互
When dragging over a navigation element (folder, tab, sidebar item), pause briefly to "spring open" that destination. Implement spring-loading on navigation containers to enable deep drop targets.
当拖拽内容经过导航元素(文件夹、标签页、侧边栏项)时,短暂停留即可“弹开”该目标。在导航容器上实现弹簧加载,以支持深层拖拽目标。
7.4 Visual Feedback for Drag and Drop
7.4 拖放的视觉反馈
Provide clear visual states:
- Lift: Item lifts with shadow when drag begins
- Move: Destination highlights when drag hovers over valid target
- Drop: Animate insertion at drop point
- Cancel: Item animates back to origin
提供清晰的视觉状态:
- 抬起:拖拽开始时,项目抬起并带有阴影
- 移动:当拖拽内容悬停在有效目标上时,目标高亮显示
- 放置:在放置点插入时添加动画
- 取消:项目动画返回原位置
7.5 Support Universal Control
7.5 支持Universal Control
Universal Control lets users drag between iPad and Mac. If your app supports drag and drop with standard and UTTypes, Universal Control works automatically.
NSItemProviderUniversal Control允许用户在iPad和Mac之间拖拽内容。如果您的应用使用标准和UTTypes支持拖放,Universal Control会自动生效。
NSItemProvider7.6 Drop Delegates for Custom Behavior
7.6 使用Drop Delegate实现自定义行为
Use for fine-grained control over drop behavior: validating drop content, reordering within lists, and handling drop position.
DropDelegateswift
struct ReorderDropDelegate: DropDelegate {
let item: Item
@Binding var items: [Item]
@Binding var draggedItem: Item?
func performDrop(info: DropInfo) -> Bool {
draggedItem = nil
return true
}
func dropEntered(info: DropInfo) {
guard let draggedItem,
let fromIndex = items.firstIndex(of: draggedItem),
let toIndex = items.firstIndex(of: item) else { return }
withAnimation {
items.move(fromOffsets: IndexSet(integer: fromIndex),
toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex)
}
}
}使用对拖放行为进行精细控制:验证拖拽内容、在列表中重新排序、处理放置位置。
DropDelegateswift
struct ReorderDropDelegate: DropDelegate {
let item: Item
@Binding var items: [Item]
@Binding var draggedItem: Item?
func performDrop(info: DropInfo) -> Bool {
draggedItem = nil
return true
}
func dropEntered(info: DropInfo) {
guard let draggedItem,
let fromIndex = items.firstIndex(of: draggedItem),
let toIndex = items.firstIndex(of: item) else { return }
withAnimation {
items.move(fromOffsets: IndexSet(integer: fromIndex),
toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex)
}
}
}8. External Display (MEDIUM)
8. 外接显示器(中等重要)
8.1 Provide Extended Content, Not Just Mirroring
8.1 显示扩展内容,而非仅镜像
When connected to an external display, show complementary content rather than duplicating the iPad screen. Presentations, reference material, or expanded views belong on the external display while controls stay on iPad.
swift
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
// Additional scene for external display
WindowGroup(id: "presentation") {
PresentationView()
}
}
}连接外接显示器时,显示补充内容而非复制iPad屏幕内容。将演示文稿、参考资料或扩展视图放在外接显示器上,同时将控件保留在iPad上。
swift
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
// 用于外接显示器的额外场景
WindowGroup(id: "presentation") {
PresentationView()
}
}
}8.2 Handle Display Connection and Disconnection
8.2 处理显示器的连接与断开
Listen for and . Transition gracefully -- if the external display disconnects mid-presentation, bring content back to the iPad screen without data loss.
UIScreen.didConnectNotificationUIScreen.didDisconnectNotification监听和通知。平稳过渡——如果外接显示器在演示过程中断开连接,将内容带回iPad屏幕且不丢失数据。
UIScreen.didConnectNotificationUIScreen.didDisconnectNotification8.3 Support Full External Display Resolution
8.3 支持外接显示器的全分辨率
Use the full resolution and aspect ratio of the external display. Do not letterbox or pillarbox your content. Query and for the connected display.
UIScreen.boundsUIScreen.scale使用外接显示器的完整分辨率和宽高比。不要为内容添加黑边。查询和获取已连接显示器的参数。
UIScreen.boundsUIScreen.scaleEvaluation Checklist
评估检查清单
Use this checklist to verify iPad-readiness:
使用此清单验证iPad适配情况:
Layout & Multitasking
布局与多任务
- App uses adaptive layout with
horizontalSizeClass - Tested at all Split View ratios (1/3, 1/2, 2/3)
- Tested in Slide Over (compact width)
- Stage Manager: resizes fluidly to arbitrary dimensions
- Multiple scenes/windows supported
- Both orientations (portrait and landscape) work correctly
- No content clipped at any size
- Safe areas respected on all iPad models
- 应用使用带有的自适应布局
horizontalSizeClass - 在所有Split View比例(1/3、1/2、2/3)下进行了测试
- 在Slide Over(紧凑宽度)下进行了测试
- Stage Manager:可流畅调整至任意尺寸
- 支持多个场景/窗口
- 横竖屏两种方向均能正常工作
- 在任何尺寸下都没有内容被裁剪
- 所有iPad型号都尊重安全区域
Navigation
导航
- Sidebar visible in regular width
- Tab bar used in compact width
- Detail view shows placeholder when no selection
- Toolbar items placed at top, not bottom
- Three-column layout used where appropriate
- Regular宽度下显示侧边栏
- Compact宽度下使用标签栏
- 未选中任何项时,详情视图显示占位符
- 工具栏项位于顶部而非底部
- 在合适的场景使用三列布局
Pointer & Trackpad
指针与触控板
- Hover effects on all interactive elements
- Right-click context menus available
- Pointer cursor adapts to content (I-beam for text, etc.)
- Click-and-drag works for reordering
- 所有交互元素都有悬停效果
- 提供右键上下文菜单
- 指针光标根据内容自适应(例如文本区域显示I型光标)
- 点击拖拽可用于重新排列内容
Keyboard
键盘
- Cmd+key shortcuts for all major actions
- Shortcuts appear in Cmd-hold overlay
- Tab key navigates between form fields
- No system shortcut conflicts
- Arrow keys navigate lists and grids
- Return/Enter activates default action
- 所有主要操作都有Cmd+按键快捷键
- 快捷键出现在长按Cmd键的覆盖层中
- Tab键可在表单输入框间导航
- 与系统快捷键无冲突
- 方向键可导航列表和网格
- 回车键激活默认操作
Apple Pencil
Apple Pencil
- Scribble works in all text fields
- Drawing apps support pressure and tilt
- Double-tap interaction handled (if applicable)
- 所有文本输入框都支持Scribble功能
- 绘图应用支持压力和倾斜感应
- 处理双击交互(如适用)
Drag and Drop
拖放
- Content can be dragged out to other apps
- Content can be dropped in from other apps
- Multi-item drag supported
- Visual feedback for all drag states
- 内容可拖拽到其他应用
- 可从其他应用拖拽内容到本应用
- 支持多项目拖拽
- 所有拖拽状态都有视觉反馈
External Display
外接显示器
- Extended content shown (not just mirror)
- Graceful handling of connect/disconnect
- 显示扩展内容(而非仅镜像)
- 平稳处理连接/断开操作
Anti-Patterns
反模式
DO NOT: Scale Up iPhone Layouts
切勿:直接放大iPhone布局
Stretching a single-column iPhone UI to fill an iPad screen wastes space, looks lazy, and provides a poor experience. Always redesign for the larger canvas.
将单列iPhone界面拉伸以填充iPad屏幕会浪费空间,显得敷衍,且体验不佳。始终为更大的画布重新设计布局。
DO NOT: Disable Multitasking
切勿:禁用多任务处理
Never opt out of multitasking support. Users expect every app to work in Split View and Slide Over. Requiring full screen is hostile to iPad workflows.
永远不要选择退出多任务支持。用户期望所有应用都能在Split View和Slide Over模式下工作。强制全屏对iPad工作流不友好。
DO NOT: Ignore the Keyboard
切勿:忽略键盘
Many iPad users have Magic Keyboard or Smart Keyboard. An app with no keyboard shortcuts forces them to reach for the screen constantly. Provide shortcuts for all frequent actions.
许多iPad用户配备Magic Keyboard或Smart Keyboard。没有键盘快捷键的应用会迫使用户频繁触摸屏幕。为所有常用操作提供快捷键。
DO NOT: Use iPhone-Style Bottom Tab Bars in Regular Width
切勿:在Regular宽度下使用iPhone式底部标签栏
Tab bars at the bottom waste vertical space on iPad and look out of place. Convert to sidebar navigation in regular width. SwiftUI does this automatically with .
.sidebarAdaptable底部标签栏会浪费iPad的垂直空间,显得格格不入。在Regular宽度下转换为侧边栏导航。SwiftUI使用可自动实现此功能。
.sidebarAdaptableDO NOT: Show Popovers as Full-Screen Sheets
切勿:将弹出框显示为全屏表单
On iPad, popovers should anchor to their source element as floating panels. Only use full-screen sheets for immersive content or flows that genuinely need the full screen. Avoid the iPhone pattern of everything being a sheet.
在iPad上,弹出框应锚定到源元素,作为浮动面板。仅在需要全屏的沉浸式内容或流程中使用全屏表单。避免采用iPhone上所有内容都以表单形式呈现的模式。
DO NOT: Ignore Pointer Hover States
切勿:忽略指针悬停状态
Missing hover effects make the app feel broken when using a trackpad. Users cannot tell what is interactive. Always add hover feedback to custom interactive elements.
缺少悬停效果会让使用触控板的用户觉得应用有问题。用户无法区分哪些元素是可交互的。始终为自定义交互元素添加悬停反馈。
DO NOT: Hardcode Dimensions
切勿:硬编码尺寸
Never hardcode widths, heights, or positions based on a specific iPad model. Use Auto Layout constraints, SwiftUI flexible frames, and for dynamic sizing.
GeometryReader永远不要基于特定iPad型号硬编码宽度、高度或位置。使用自动布局约束、SwiftUI灵活框架和实现动态尺寸。
GeometryReaderDO NOT: Forget Drag and Drop
切勿:忘记拖放功能
On iPad, drag and drop between apps is a core workflow. Not supporting it makes your app a dead end for content. At minimum, support dragging text, images, and URLs in and out.
在iPad上,应用间拖放是核心工作流之一。不支持拖放会让您的应用成为内容的死胡同。至少支持文本、图片和URL的拖入拖出。
DO NOT: Override System Keyboard Shortcuts
切勿:覆盖系统键盘快捷键
Claiming Cmd+H, Cmd+Tab, Cmd+Space, or Globe shortcuts will not work and confuses users who expect system behavior. Check Apple's reserved shortcuts list before assigning.
占用Cmd+H、Cmd+Tab、Cmd+Space或地球键快捷键无法生效,还会让期望系统默认行为的用户感到困惑。分配快捷键前,请查阅Apple的预留快捷键列表。
DO NOT: Present Dense Content Without Scrolling
切勿:显示密集内容却不支持滚动
Large iPad screens tempt designers to show everything at once. Content should still scroll when it exceeds the visible area. Never truncate content to avoid scrolling.
iPad大屏幕容易诱使设计师一次性展示所有内容。当内容超出可见区域时,仍应支持滚动。切勿为避免滚动而截断内容。