关于 swiftui-iphone-duo
用于检查并调整 SwiftUI 应用,使其适应不同窗口尺寸和 iPhone Duo 硬件的技能。它优先改进通用自适应布局,再考虑折叠屏适配和 Duo 专属功能。
主要功能
- 01自适应布局审查
- 02导航与工具栏指引
- 03折叠区域安全定位
- 04分层 Duo API 指引
- 05模拟器验证流程
适用场景
- 01重构设备特定布局判断
- 02适配多任务窗口宽度
- 03检查折叠区域附近的控件
- 04规划经过验证的 Duo 专属行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ flowritescode/ fwc-swiftui-skills --skill swiftui-iphone-duo安装后在 Claude Code 中输入/swiftui-iphone-duo确认已加载。
附带文件reference.md
详细介绍
SwiftUI iPhone Duo
不要为这个应用单独设计一个“Duo 版本”。
首先构建自适应 SwiftUI 界面,使其能够适应不断变化的宽度和高度。只有在折叠处、铰链、第二块显示屏或垂直系统栏能显著提升体验时,才添加 Duo 专属行为。
目标不是“让这个应用支持 iPhone Duo”。目标是:
让这个应用在各种尺寸下都表现出色,然后在能创造额外价值时利用 Duo 的独特硬件。
在检查或更改布局之前,请先阅读完整规则手册:reference.md。
适用场景
- 用户要求支持 iPhone Duo、可折叠 iPhone、铰链、折叠或两块显示屏。
- 用户要求实现跨紧凑 → 宽屏的自适应 SwiftUI 布局,包括多任务处理。
- 代码使用
UIDevice、UIScreen.main(bounds 或 scale)、设备类型、方向、isDuo或isFolded来控制布局。 - 工作涉及垂直栏、工具栏项目排序/溢出、工作表放置、
ArrangementView、保留区域、onHingeChange/UIHingeInteraction或CameraCaptureAccessory。 - 项目迁移到 iOS 27.1 SDK(该版本会启用全屏布局和垂直栏)。
相关技能
| 技能 | 何时加载 |
|---|---|
| swiftui-liquid-glass(此仓库) | iOS 26+ 上的系统栏和玻璃质感界面 |
| App Resizability(Apple,Xcode 27.1) | 初步扫描调整大小和 Duo 相关问题。使用 xcrun agent skills export 导出,供其他 Agent 使用 |
优化顺序
- 自适应布局
- 自适应导航
- 自适应工具栏和标签栏
- 避开折叠处的内容布局
- Duo 专属布局
- 铰链驱动的交互
- 第二显示屏体验
渐进式 API 层级
编写代码前,先对每项更改进行分类。提出 Tier 2 或 Tier 3 之前,务必先完成 Tier 1。
Tier 1 — 通用自适应改进(首先完成):
NavigationSplitView
adaptive TabView
adaptive grids
ViewThatFits
AnyLayout
size classes
container-relative sizing
system toolbars
safe-area correctness
这些改进适用于所有 Apple 平台和窗口尺寸。
Tier 2 — Duo 感知布局(仅在需要时):
reserved regions (reservedRegions(kind:options:))
ArrangementView
vertical bar tuning (axisBehavior, visibilityPriority, compression, toolbarVerticalEdge)
toolbarVerticalBehavior(.disabled), only for the documented exceptions
sheet placement (presentationPlacement)
Duo-specific safe-area handling
Tier 3 — Duo 专属体验(仅在产品能从中受益时):
onHingeChange / UIHingeInteraction
hinge angle
CameraCaptureAccessory (scene accessory, camera apps only)
multi-scene workflows (new windows only on the inner display)
工作流程
复制并跟踪进度:
- [ ] 1. Read reference.md (start with "Platform facts")
- [ ] 2. Check the SDK: full-screen layout and vertical bars need an iOS 27.1 SDK build (Xcode 27.1)
- [ ] 3. Review screens with the decision tree
- [ ] 4. Flag red-flag patterns with file evidence
- [ ] 5. Classify each change as Tier 1 / 2 / 3
- [ ] 6. Implement Tier 1 first
- [ ] 7. Apply Tier 2/3 only when space-based layout is insufficient; gate 27.1 APIs with #available
- [ ] 8. Keep state above adaptive layout; verify continuity across widths and every pose in Device Hub
1) 检查现有 UI
使用下方的决策树检查每个 SwiftUI 屏幕。标记以下情况:
- 使用设备身份切换布局(
UIDevice、设备类型、型号、isDuo、isFolded) - 使用
UIScreen.main(bounds、scale、存储的屏幕)或方向控制普通布局 - 将
horizontalSizeClass == .regular视为“iPad” - 仅读取一次尺寸(在启动时或
viewIsAppearing中),之后不再读取 - 固定列数、硬编码侧边栏宽度、随意使用
if width > N - 紧凑与展开视图层级分开,导致状态重复
- 无法移到垂直边缘的自定义工具栏/标签栏
- 工具栏项目有标题却没有图标,或使用自定义“...”菜单代替系统溢出菜单
- 重要内容可能落在折叠处
- 宽屏布局只是拉伸内容,而没有呈现层级结构
- 使用铰链角度决定侧边栏、列或导航
2) 实现或重构
- 用容器空间取代设备检查:尺寸类别、
ViewThatFits、AnyLayout、自适应网格、containerRelativeFrame/onGeometryChange。 - 对于集合 → 选择 → 详情,优先使用
NavigationSplitView。优先采用自适应TabView,而非手工构建侧边栏:.tabViewStyle(.sidebarAdaptable)加上.defaultTabBarPlacement(.sidebar)可在内屏启用侧边栏(在 iPhone 上,单独使用.sidebarAdaptable会显示标签栏)。 - 在
NavigationStack/NavigationSplitView中,优先使用系统.toolbar/ToolbarItem/ToolbarOverflowMenu,以便工具栏可以变为纵向排列。为每个项目设置标题和图标;先放关闭(.cancellationAction),再放完成(.topBarPinnedTrailing);设置visibilityPriority。 - 保留一个视图层级;将导航、滚动、选择、编辑器和播放状态提升到布局之上。
- 将额外宽度用于窗格、检查器、列和常驻导航,而不是拉长文本行。限制可读内容的宽度(例如
.frame(maxWidth: 700))。 - 将对折叠状态敏感的控件移到本地。不要仅仅因为出现了保留区域就重建整个屏幕。
- 仅在一种双部分体验中使用
ArrangementView(播放器 + 播放列表、编辑器 + 检查器)。不要将它用作应用导航。 - 仅在涉及物理交互时使用
onHingeChange/ 铰链角度。布局响应空间。交互可以响应铰链状态。 对于适配折叠的布局,请使用保留区域或ArrangementView。 - 不要将
innerDisplay/outerDisplay作为独立画布。唯一受支持的外屏内容是在摄像头采集会话处于活动状态时显示CameraCaptureAccessory。 - 在每种姿态下检查每个工作表;使用
presentationPlacement(_:)选择位置。
3) 无法测试的 Duo 行为
Xcode 27.1 包含 iPhone Duo 模拟器(设备中心:打开、合上、旋转、折叠)。它无法运行大多数应用扩展,也没有摄像头,因此摄像头采集配件需要使用设备。
在模拟器或设备上验证特定行为之前:
Agent 可以:
- 改进通用适配能力
- 移除对设备的假设
- 采用标准自适应容器
- 为 Duo 专用 API 预备代码边界
- 识别可能对折叠状态敏感的 UI
Agent 应避免:
- 硬编码预测的铰链坐标
- 猜测 Duo 的精确尺寸
- 添加未经测试的 Duo 专属布局分支
- 基于假设重构正常工作的屏幕
如果暂时无法在模拟器或设备上验证 Duo 专属行为,应优先做好准备,而不是进行推测性实现。
Agent 决策树
审核 SwiftUI 屏幕时,请按以下顺序评估。
-
布局能否适应持续变化的宽度?
如果不能:先修复通用自适应布局。 -
导航是否在手机和平板实现之间手动切换?
如果是:研究NavigationSplitView、自适应TabView或其他系统导航容器。 -
是否存在固定宽度或对屏幕尺寸的假设?
如果是:尽可能将其替换为相对于容器的布局。 -
宽屏布局是否只是简单拉伸?
如果是:考虑添加侧边栏、详细信息窗格、检查器、额外列或补充内容。 -
重要内容是否可能与折叠线相交?
如果是:使用能感知预留区域的定位方式。 -
两个相关视图是否会在不同布局之间手动重新排列?
如果是:评估ArrangementView、ViewThatFits或AnyLayout。 -
是否使用了自定义工具栏或标签栏,或者工具栏项没有图标?
如果是:确定能否用 SwiftUI 系统栏替代并实现垂直适配,并为每个项目提供标题和图标。 -
所需行为是否确实取决于物理铰链的位置?
如果不是:不要使用铰链 API。
如果是:使用onHingeChange(UIKit:UIHingeInteraction)和hinge.status/hinge.angle。 -
拍摄期间,外屏是否能提供有用的补充信息?
如果是:评估CameraCaptureAccessory。否则,不要尝试指定第二块屏幕。
Agent 规则
这些规则必须严格遵守。完整说明和代码请参阅 reference.md。
- 遇到设备特定的布局逻辑时,先尝试改用基于可用容器空间的布局行为。
- 优先使用语义化的自适应容器,而不是手动设置断点。顺序:系统导航/容器 → 自适应网格 →
ViewThatFits→ 尺寸类别 → 最后才使用精确几何尺寸。 - 如果屏幕包含主从导航,应优先使用
NavigationSplitView,而不是手动构建HStack侧边栏。 - 不要无限拉伸狭窄的界面。利用额外空间提升信息密度,或加入互补面板。
- 如果重复内容以网格形式呈现,应优先使用由最小项宽度驱动的自适应列(
GridItem(.adaptive(minimum:)))。 - 当问题是“哪种排列方式放得下?”而不是“我当前使用的是哪种设备?”时,使用
ViewThatFits。 - 优先更改布局容器(
AnyLayout),而不是有条件地重建不同的视图层级。 - 绝不要使用
UIScreen.main(包括其 bounds、scale 或存储的引用)来布局。Apple 不鼓励这种做法,并计划弃用对主屏幕的引用。 - 避免让重要的交互内容或语义内容跨越活动分割区域。装饰性背景和滚动内容通常可以跨越折叠处。
- 遇到折叠干扰时,先在局部处理,再进行全局结构更改。
- 仅当两个视图共同构成一个自适应体验时才使用
ArrangementView;不要用它代替应用导航。 - 创建自定义工具栏之前,先确认该设计无法通过 SwiftUI 的工具栏 API 实现。
- 主要工具栏操作必须始终可见;随着可用栏空间减少,次要操作可以移入溢出菜单。
- 如果标签页代表应用的主要部分,且宽屏布局适合使用常驻导航,则优先采用 SwiftUI 的自适应侧边栏系统(
.sidebarAdaptable+.defaultTabBarPlacement(.sidebar))。 - 绝不要手动将一个安全区域内边距镜像到另一条边。Duo 的安全区域可能不对称。
- 将折叠处视作书脊:背景可以跨越,精确定位的内容则不应跨越。
- 布局应响应空间变化。交互可以响应铰链状态。不要使用
hinge.angle控制侧边栏、列数、网格数量或导航折叠。 - 仅在相机拍摄期间将
CameraCaptureAccessory用于补充内容;主要体验应始终附着于主场景。 - 布局转换不能变成应用状态转换。
- 每种扩展布局都必须能平稳地经过中间宽度,回到紧凑布局。展开状态不代表应用处于宽屏模式。
- 可用宽度增加,不意味着文本行就应更宽。
- 宽屏布局应展现更多有用的结构,而不只是更多空白。
- 优化触达范围和分组,而不是追求最大的几何分布。
- 提出 Tier 2 或 Tier 3 更改之前,务必先完成 Tier 1。
- 如果尚无法在模拟器或设备上验证 Duo 特定行为,应优先做好准备,而不是进行推测性实现。
- 检查每种姿态下的每个工作表;应有意设置其位置,而不是构建自定义呈现方式。
- 绝不要在没有与项目部署目标相匹配的可用性检查时调用 27.1 Duo API。
- 所有填充模式的图像或视频都必须确保重要内容从窄幅外屏到宽幅内屏始终可见。
代码审查中的危险信号
在用于常规布局决策时,应标记以下内容:
UIScreen.main.bounds
UIScreen.main.scale
UIWindow(frame: UIScreen.main.bounds)
UIDevice.current.userInterfaceIdiom == .pad
UIDevice.current.orientation / statusBarOrientation / interfaceOrientation
if orientation == .landscape
if horizontalSizeClass == .regular { iPadLayout }
bounds.height == 844
view.bounds.width - view.safeAreaInsets.left * 2
if isIPhoneDuo
if isFolded { ... }
还应标记:
- 固定的大型框架
- 硬编码的侧边栏宽度
- 固定的网格列数
- 自定义的仿制工具栏(或自定义的
UIToolbar/UINavigationBar/UITabBar实例) - 只有标题的工具栏项目(它们不会垂直排列)
- 自定义的“...”溢出菜单
- 内容直接横跨折叠处居中
- 紧凑状态和展开状态重复维护
- 仅在两种宽度下测试布局
- 过多的全宽文本
- 控件放置在安全区域之外
- 没有焦点位置的
.scaleAspectFill/.aspectRatio(contentMode: .fill)主视觉媒体 - 在文档所述例外情况之外使用
toolbarVerticalBehavior(.disabled),或按视图状态切换该设置
首选替代方案见 reference.md。
审查清单
- 没有
if isDuo/ idiom / orientation /UIScreen布局分支 - 布局会随容器空间从窄 → 中等 → 宽而变化
- 列表/详情界面使用
NavigationSplitView,并保留选择状态 - 网格使用
GridItem(.adaptive(minimum:)),而不是固定列数 - 局部重排使用
ViewThatFits或AnyLayout,而非重复的视图层级 - 宽屏布局通过侧边栏、详情、检查器和分栏展现层级,而不是拉伸内容
- 可读内容设有最大宽度
- 应用可使用 iOS 27.1 SDK 构建;27.1 API 均设有可用性检查
- 使用系统工具栏/标签栏;项目可水平和垂直排列
- 每个工具栏项目都有标题和图标;先放关闭/返回,再放完成;设置溢出优先级
- 重要控件位于(可能不对称的)安全区域内
- 关键内容不会在折叠处居中
- 状态(导航、滚动、选择、编辑器、播放)在折叠/显示变化后仍得以保留
- 检查所有形态下的工作表;在需要时设置其位置
- 检查分屏视图中的应用位于左侧和右侧时的效果
- 仅将铰链 API 用于实体交互
- 仅通过
CameraCaptureAccessory显示外屏内容,不手动指定显示目标 - 只有在完成 Tier 1 且可以测试时,才添加 Tier 2/3 API
其他资源
- 完整的 28 条规则、平台事实、API 参考和改造前后示例:reference.md
- Apple:为 iPhone Duo 准备应用、针对 iPhone Duo 进行设计、让应用在 iPhone Duo 上大放异彩的三个步骤