swiftui-iphone-duo
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSwiftUI iPhone Duo
SwiftUI iPhone Duo
Do not design a separate “Duo version” of the app.
Start with an adaptive SwiftUI interface that works across continuously changing widths and heights. Add Duo-specific behavior only when the fold, hinge, second display, or vertical system bars materially improve the experience.
The target is not “Make this app support iPhone Duo.” The target is:
Make this app excellent at every size, then use Duo's unique hardware where it creates additional value.
Before reviewing or changing layout, read the full rulebook: reference.md.
不要为应用设计单独的“Duo版本”。
首先构建可适配宽高持续变化的自适应SwiftUI界面。仅当折叠、铰链、副显示屏或垂直系统栏能显著提升体验时,再添加Duo专属功能。
我们的目标不是“让这款应用支持iPhone Duo”,而是:
让这款应用在所有尺寸下都表现出色,再利用Duo的独特硬件创造额外价值。
在审查或修改布局前,请阅读完整规则手册:reference.md。
When to use
适用场景
- User asks to support iPhone Duo, a foldable iPhone, hinge, fold, or two displays.
- User asks for adaptive SwiftUI layout across compact → wide, including multitasking.
- Code uses ,
UIDevice, idiom, orientation,UIScreen.main.bounds, orisDuofor layout.isFolded - Work involves , reserved regions,
ArrangementView, or scene accessories.onHingeChange
- 用户要求支持iPhone Duo、可折叠iPhone、铰链、折叠或双显示屏。
- 用户要求实现从紧凑到宽屏的自适应SwiftUI布局,包括多任务场景。
- 代码中使用、
UIDevice、idiom、orientation、UIScreen.main.bounds或isDuo来处理布局。isFolded - 工作涉及、Reserved Regions、
ArrangementView或scene accessories。onHingeChange
Related skills
相关技能
| Skill | When to load |
|---|---|
| swiftui-whats-new-27 | Toolbar overflow, |
| swiftui-specialist | Broader SwiftUI layout and navigation correctness |
| swiftui-liquid-glass | System bars and glass chrome on iOS 26+ |
| 技能 | 加载时机 |
|---|---|
| swiftui-whats-new-27 | 工具栏溢出、 |
| swiftui-specialist | 更广泛的SwiftUI布局与导航正确性问题 |
| swiftui-liquid-glass | iOS 26及以上版本的系统栏与玻璃质感界面 |
Optimization order
优化顺序
- Adaptive layout
- Adaptive navigation
- Adaptive toolbars and tabs
- Fold-safe positioning
- Duo-specific arrangements
- Hinge-driven interactions
- Second-display experiences
- 自适应布局
- 自适应导航
- 自适应工具栏与标签页
- 折叠安全定位
- Duo专属排布
- 铰链驱动交互
- 副屏体验
Progressive API tiers
渐进式API层级
Classify every change before writing code. Always complete Tier 1 before proposing Tier 2 or Tier 3.
Tier 1 — Universal adaptive improvements (do these first):
text
NavigationSplitView
adaptive TabView
adaptive grids
ViewThatFits
AnyLayout
size classes
container-relative sizing
system toolbars
safe-area correctnessThese benefit all Apple platforms and window sizes.
Tier 2 — Duo-aware layout (only when needed):
text
Reserved Regions
ArrangementView
vertical toolbar behavior
Duo-specific safe-area handlingTier 3 — Duo-exclusive experiences (only when the product benefits):
text
onHingeChange
hinge angle
scene accessories
multi-display interactions
multi-scene Duo workflows编写代码前先对所有修改进行分类。必须先完成第1层,再提出第2或第3层的修改。
第1层 — 通用自适应改进(优先执行):
text
NavigationSplitView
adaptive TabView
adaptive grids
ViewThatFits
AnyLayout
size classes
container-relative sizing
system toolbars
safe-area correctness这些改进适用于所有Apple平台和窗口尺寸。
第2层 — Duo感知布局(仅在需要时使用):
text
Reserved Regions
ArrangementView
vertical toolbar behavior
Duo-specific safe-area handling第3层 — Duo专属体验(仅当产品能从中受益时使用):
text
onHingeChange
hinge angle
scene accessories
multi-display interactions
multi-scene Duo workflowsWorkflow
工作流程
Copy and track progress:
- [ ] 1. Read reference.md
- [ ] 2. Review screens with the decision tree
- [ ] 3. Flag red-flag patterns with file evidence
- [ ] 4. Classify each change as Tier 1 / 2 / 3
- [ ] 5. Implement Tier 1 first
- [ ] 6. Apply Tier 2/3 only when space-based layout is insufficient
- [ ] 7. Keep state above adaptive layout; verify continuity across widths复制并跟踪进度:
- [ ] 1. Read reference.md
- [ ] 2. Review screens with the decision tree
- [ ] 3. Flag red-flag patterns with file evidence
- [ ] 4. Classify each change as Tier 1 / 2 / 3
- [ ] 5. Implement Tier 1 first
- [ ] 6. Apply Tier 2/3 only when space-based layout is insufficient
- [ ] 7. Keep state above adaptive layout; verify continuity across widths1) Review existing UI
1) 审查现有UI
Walk every SwiftUI screen with the decision tree below. Flag:
- Device identity used as a layout switch (, idiom, model,
UIDevice,isDuo)isFolded - or orientation used for ordinary layout
UIScreen.main.bounds - Fixed column counts, hardcoded sidebar widths, arbitrary
if width > N - Separate compact vs expanded view hierarchies with duplicated state
- Custom toolbars / tab bars that cannot move to a vertical edge
- Critical content that would sit on the fold
- Wide layouts that only stretch instead of exposing hierarchy
- Hinge angle used to decide sidebar, columns, or navigation
按照下方的决策树逐一检查每个SwiftUI界面。标记以下问题:
- 将设备标识用作布局切换依据(、idiom、机型、
UIDevice、isDuo)isFolded - 使用或orientation处理常规布局
UIScreen.main.bounds - 固定列数、硬编码侧边栏宽度、随意的判断
if width > N - 紧凑与展开视图层级分离,状态重复
- 无法移动到垂直边缘的自定义工具栏/标签栏
- 会落在折叠线上的关键内容
- 宽屏布局仅拉伸内容,未展现层级结构
- 使用铰链角度决定侧边栏、列数或导航
2) Implement or refactor
2) 实现或重构
- Replace device checks with container space: size classes, ,
ViewThatFits, adaptive grids,AnyLayout/containerRelativeFrame.onGeometryChange - Prefer for collection → selection → detail. Prefer adaptive
NavigationSplitView(TabView) over a hand-built sidebar..sidebarAdaptable - Prefer system /
.toolbar/ToolbarItemso bars can become vertical.ToolbarOverflowMenu - Keep one view hierarchy; hoist navigation, scroll, selection, editor, and playback state above layout.
- Use extra width for panes, inspectors, columns, and persistent navigation — not longer text lines. Cap readable content (e.g. ).
.frame(maxWidth: 700) - Move fold-sensitive controls locally. Do not rebuild the whole screen because a reserved region appeared.
- Use only for one two-part experience (player + playlist, editor + inspector). Do not use it as app navigation.
ArrangementView - Use / hinge angle only for physical interaction. Layout reacts to space. Interaction may react to hinge state.
onHingeChange - For the outer display, use scene accessories. Do not target /
innerDisplayas independent canvases.outerDisplay
- 用容器空间替代设备检查:size classes、、
ViewThatFits、自适应网格、AnyLayout/containerRelativeFrame。onGeometryChange - 对于集合→选择→详情的结构,优先使用。优先使用自适应
NavigationSplitView(TabView)而非手动构建的侧边栏。.sidebarAdaptable - 优先使用系统/
.toolbar/ToolbarItem,以便工具栏可转为垂直布局。ToolbarOverflowMenu - 保持单一视图层级;将导航、滚动、选择、编辑器和播放状态提升到布局之上。
- 将额外宽度用于窗格、检查器、列和持久导航——而非拉长文本行。为可读内容设置最大宽度(例如)。
.frame(maxWidth: 700) - 局部移动对折叠敏感的控件。不要因为出现Reserved Regions而重建整个界面。
- 仅用于由两部分组成的体验(播放器+播放列表、编辑器+检查器)。不要将其用作应用导航。
ArrangementView - / 铰链角度仅用于物理交互。布局响应空间变化,交互可响应铰链状态。
onHingeChange - 对于外屏,使用scene accessories。不要将/
innerDisplay作为独立画布来开发。outerDisplay
3) Untestable Duo behavior
3) 暂无法测试的Duo行为
Until the project can be tested with the iPhone Duo simulator in Xcode 27.1:
The agent may:
- improve general adaptability
- remove device assumptions
- adopt standard adaptive containers
- prepare code boundaries for Duo-specific APIs
- identify likely fold-sensitive UI
The agent should avoid:
- hardcoding predicted hinge coordinates
- guessing exact Duo dimensions
- adding untested Duo-only layout branches
- restructuring working screens around assumptions
If Duo-specific behavior cannot yet be verified in the simulator, prefer preparation over speculative implementation.
在项目可通过Xcode 27.1中的iPhone Duo模拟器进行测试之前:
Agent 可以:
- 提升通用适配性
- 移除设备相关假设
- 采用标准自适应容器
- 为Duo专属API预留代码边界
- 识别可能受折叠影响的UI
Agent 应当避免:
- 硬编码预测的铰链坐标
- 猜测Duo的精确尺寸
- 添加未经测试的Duo专属布局分支
- 基于假设重构正常运行的界面
如果Duo专属行为尚无法在模拟器中验证,优先做好准备,而非投机式实现。
Agent decision tree
Agent决策树
When reviewing a SwiftUI screen, evaluate it in this order.
-
Does the layout work across continuously changing widths?
If no: fix the general adaptive layout first. -
Is navigation manually switching between phone and tablet implementations?
If yes: investigate, adaptiveNavigationSplitView, or another system navigation container.TabView -
Are there fixed widths or screen-size assumptions?
If yes: replace them with container-relative layout where possible. -
Does the wide layout simply stretch?
If yes: look for a sidebar, detail pane, inspector, additional columns, or supplementary content. -
Could important content intersect the fold?
If yes: use reserved-region-aware positioning. -
Are two related views being manually rearranged across layouts?
If yes: evaluate,ArrangementView, orViewThatFits.AnyLayout -
Is there a custom toolbar or tab bar?
If yes: determine whether SwiftUI system bars can replace it and adapt vertically. -
Does the requested behavior genuinely depend on physical hinge position?
If no: do not use the hinge API.
If yes: useand hinge state/angle.onHingeChange -
Would the outer display provide useful supplementary information?
If yes: evaluate a scene accessory. Do not manually target a second screen.
审查SwiftUI界面时,按以下顺序评估:
-
布局是否能适配持续变化的宽度?
若不能:先修复通用自适应布局。 -
导航是否在手机和平板实现之间手动切换?
若是:调研、自适应NavigationSplitView或其他系统导航容器。TabView -
是否存在固定宽度或屏幕尺寸假设?
若是:尽可能用容器相对布局替换它们。 -
宽屏布局是否只是单纯拉伸?
若是:考虑添加侧边栏、详情窗格、检查器、额外列或补充内容。 -
重要内容是否会与折叠线相交?
若是:使用支持Reserved Regions的定位方式。 -
两个相关视图是否在不同布局间手动重排?
若是:评估是否可使用、ArrangementView或ViewThatFits。AnyLayout -
是否存在自定义工具栏或标签栏?
若是:判断是否可用SwiftUI系统栏替代并支持垂直适配。 -
需求的行为是否确实依赖物理铰链位置?
若否:不要使用铰链API。
若是:使用及铰链状态/角度。onHingeChange -
外屏是否能提供有用的补充信息?
若是:评估使用scene accessory。不要手动针对副屏开发。
Agent rules
Agent规则
These are strict. Full explanations and code are in reference.md.
- When encountering device-specific layout logic, first attempt to replace it with layout behavior based on available container space.
- Prefer semantic adaptive containers over manual breakpoints. Order: system navigation/container → adaptive grid → → size classes → exact geometry last.
ViewThatFits - If a screen contains master/detail navigation, strongly prefer over a manually constructed
NavigationSplitViewsidebar.HStack - Do not stretch narrow interfaces indefinitely. Use extra space to increase information density or introduce complementary panes.
- If repeated content appears in a grid, prefer minimum-item-width-driven adaptive columns ().
GridItem(.adaptive(minimum:)) - Use when the question is “which arrangement fits?” rather than “which device am I on?”
ViewThatFits - Prefer changing layout containers () over conditionally rebuilding separate view hierarchies.
AnyLayout - Never use for SwiftUI layout unless there is an exceptional non-layout requirement.
UIScreen.main.bounds - Avoid placing important interactive or semantic content across an active division region. Decorative backgrounds and scrolling content may usually cross the fold.
- Respond to fold interference locally before making a global structural change.
- Use only when the two views form one adaptive experience; do not substitute it for app navigation.
ArrangementView - Before creating a custom toolbar, verify that the design cannot be expressed with SwiftUI's toolbar APIs.
- Primary toolbar actions must remain visible; secondary actions may move into overflow as available bar space decreases.
- If tabs represent primary app sections and the wide layout benefits from persistent navigation, prefer SwiftUI's adaptive sidebar system.
- Never manually mirror one safe-area inset onto another edge. Duo safe areas can be asymmetric.
- Treat the fold like the spine of a book: backgrounds may span it; precise content should not.
- Layout reacts to space. Interaction may react to hinge state. Do not use for sidebar, columns, grid count, or navigation collapse.
hinge.angle - Use scene accessories for intentionally secondary display content; keep the main experience attached to the primary scene.
- A layout transition must not become an application-state transition.
- Every expansive layout must have a graceful path back through intermediate widths to compact presentation. Unfolded does not mean wide app.
- More available width does not imply wider text lines.
- Wide layouts should reveal more useful structure, not just more whitespace.
- Optimize for reach and grouping, not maximum geometric distribution.
- Always complete Tier 1 before proposing Tier 2 or Tier 3 changes.
- If Duo-specific behavior cannot yet be verified in the simulator, prefer preparation over speculative implementation.
这些是严格规则。完整说明和代码示例见reference.md。
- 遇到设备专属布局逻辑时,首先尝试用基于可用容器空间的布局行为替换。
- 优先使用语义化自适应容器,而非手动断点。优先级顺序:系统导航/容器 → 自适应网格 → → size classes → 最后才是精确几何计算。
ViewThatFits - 如果界面包含主从导航,强烈优先使用而非手动构建的
NavigationSplitView侧边栏。HStack - 不要无限拉伸窄界面。利用额外空间提升信息密度或引入补充窗格。
- 如果网格中存在重复内容,优先使用基于最小项宽度的自适应列()。
GridItem(.adaptive(minimum:)) - 当问题是“哪种排布适合?”而非“我在哪种设备上?”时,使用。
ViewThatFits - 优先更换布局容器(),而非条件性重建独立的视图层级。
AnyLayout - 绝不要在SwiftUI布局中使用,除非有特殊的非布局需求。
UIScreen.main.bounds - 避免将重要的交互或语义内容放置在活动分割区域上。装饰性背景和滚动内容通常可以跨越折叠线。
- 先局部响应折叠干扰,再进行全局结构修改。
- 仅用于两个视图构成一个自适应体验的场景;不要用它替代应用导航。
ArrangementView - 创建自定义工具栏前,先确认该设计无法用SwiftUI的工具栏API实现。
- 主要工具栏操作必须保持可见;当工具栏可用空间减少时,次要操作可移入溢出菜单。
- 如果标签页代表应用主要板块,且宽屏布局能从持久导航中受益,优先使用SwiftUI的自适应侧边栏系统。
- 绝不要将一个安全区内边距手动镜像到另一边缘。Duo的安全区可能是不对称的。
- 将折叠线视为书脊:背景可以跨越它;精确内容不应跨越。
- 布局响应空间变化,交互可响应铰链状态。不得使用控制侧边栏、列数、网格数量或导航折叠。
hinge.angle - 专为副屏设计的内容使用scene accessories;主体验始终依附于主场景。
- 布局过渡绝不能变成应用状态过渡。
- 所有展开布局都必须能通过中间宽度顺畅回退到紧凑展示形态。展开状态不等于应用就是宽屏的。
- 可用宽度增加不代表文本行就要更宽。
- 宽屏布局应当展现更多有用的结构,而非仅仅增加空白。
- 针对可触达性和分组进行优化,而非最大化几何分布。
- 提出第2或第3层修改前,必须先完成第1层。
- 如果Duo专属行为尚无法在模拟器中验证,优先做好准备,而非投机式实现。
Code-review red flags
代码审查红旗项
Flag these when used for ordinary layout decisions:
swift
UIScreen.main.bounds
UIDevice.current.userInterfaceIdiom == .pad
if orientation == .landscape
if isIPhoneDuo
if isFolded { ... }Also flag:
- fixed large frames
- hardcoded sidebar widths
- fixed grid column counts
- custom fake toolbars
- content centered directly across the fold
- duplicated compact and expanded state
- layouts tested only at two widths
- excessive full-width text
- controls placed outside safe areas
Preferred replacements are in reference.md.
当以下内容用于常规布局决策时,标记为红旗项:
swift
UIScreen.main.bounds
UIDevice.current.userInterfaceIdiom == .pad
if orientation == .landscape
if isIPhoneDuo
if isFolded { ... }同时标记以下问题:
- 固定大尺寸frame
- 硬编码侧边栏宽度
- 固定网格列数
- 自定义非系统工具栏
- 内容直接居中跨越折叠线
- 紧凑与展开状态重复
- 仅在两种宽度下测试的布局
- 过多的全宽文本
- 控件放置在安全区外
推荐的替代方案见reference.md。
Review checklist
审查清单
- No / idiom / orientation /
if isDuolayout branchesUIScreen - Layout follows container space across narrow → intermediate → wide
- List/detail uses with preserved selection
NavigationSplitView - Grids use rather than fixed column counts
GridItem(.adaptive(minimum:)) - Local rearrangements use or
ViewThatFits, not duplicate hierarchiesAnyLayout - Wide layout exposes hierarchy (sidebar, detail, inspector, columns) instead of stretching
- Readable content has a maximum width
- System toolbars/tabs used; items work horizontally and vertically
- Important controls stay in (possibly asymmetric) safe areas
- Critical content is not centered on the fold
- State (nav, scroll, selection, editors, playback) survives fold/display changes
- Hinge APIs used only for physical interaction
- Second display uses scene accessories, not manual display targeting
- Tier 2/3 APIs added only after Tier 1, and only when testable
- 没有基于/ idiom / orientation /
if isDuo的布局分支UIScreen - 布局在窄→中→宽范围内均遵循容器空间变化
- 列表/详情使用且保留选择状态
NavigationSplitView - 网格使用而非固定列数
GridItem(.adaptive(minimum:)) - 局部重排使用或
ViewThatFits,而非重复层级AnyLayout - 宽屏布局展现层级结构(侧边栏、详情、检查器、列)而非拉伸内容
- 可读内容设置了最大宽度
- 使用系统工具栏/标签页;项目支持水平和垂直布局
- 重要控件位于(可能不对称的)安全区内
- 关键内容未居中在折叠线上
- 状态(导航、滚动、选择、编辑器、播放)在折叠/显示屏切换时保持不变
- 铰链API仅用于物理交互
- 副屏使用scene accessories,而非手动针对显示屏开发
- 第2/3层API仅在第1层完成后添加,且仅在可测试时添加
Additional resources
更多资源
- Full 25 rules, API sketches, and before/after transformations: reference.md
- 完整的25条规则、API示意图及改造前后对比:reference.md