小白 / Xiaobai

小白 / Xiaobai

开发者 · 产品构建者

持续构建 AI 工程系统、开发者工具与长期数字资产。

关于作者与 XBSTACK →
iPhone Duo UIKit 适配指南:动态布局、Size Classes、Safe Area、Reserved Regions 与系统导航

iPhone Duo 怎么适配?Apple 官方指南下的 UIKit、Tab Bar 与折叠布局实战

基于 Apple 最新 iPhone Duo 官方文档,系统梳理 UIKit App 的 Size Classes、系统导航、自定义 Tab Bar、Safe Area、Reserved Regions、折叠姿态与 Xcode 27.1 测试方法。

发布 · 2026-09-2810 分钟阅读XBSTACK 原创
#iPhone Duo#UIKit#iOS 27.1#Size Classes#Safe Area#Reserved Regions

如果你已经有一个正常运行的 iPhone App,iPhone Duo 到来以后,最容易产生的误解是:是不是必须专门为折叠屏重新设计一套 UI?

按照 Apple 当前公开的 iPhone Duo 设计指南 和 开发准备指南,答案不是“重新做一套 Duo 界面”。真正需要解决的是 Resizability(动态尺寸适配):App 要能够随着外屏、内屏、部分折叠和 Split View 的可用空间变化,自然调整内容与控件。

Apple 的核心建议可以归纳为四点:使用 Size Classes,而不是设备朝向决定主要布局;使用 layout margins 和 Safe Area,避免固定宽度和特定屏幕假设;优先采用系统导航容器;复杂自定义界面通过 Reserved Regions 处理相机遮挡和折叠分割区域。

先从固定屏幕假设开始清理

过去很多 UIKit 项目默认“屏幕就是一个固定矩形”,于是会直接拿整块屏幕宽度做业务布局:

CGFloat screenWidth = UIScreen.mainScreen.bounds.size.width;

这行代码本身不是错误,但如果页面主布局长期依赖固定的设备宽度,就需要重新检查。Apple 在 iPhone Duo 的指导中明确要求避免固定宽度和 display-specific dependencies。

对于当前 View,更合理的是根据当前容器尺寸布局:

CGFloat width = CGRectGetWidth(self.view.bounds);

如果使用 Auto Layout,则让约束更多依赖:

self.view.safeAreaLayoutGuide

核心思想不是“检测 iPhone Duo”,而是根据当前真正拥有的空间布局。

使用 Size Classes,而不是横竖屏判断布局

Apple 在 Prepare your app for iPhone Duo 中明确提出,应该使用 Size Classes,而不是 interface orientation,决定界面如何变化。

Size Classes 在紧凑宽度和常规宽度之间切换单栏与双栏布局

典型列表详情界面可以这样理解:

紧凑宽度
→ 单栏列表
→ 点击进入详情

常规宽度
→ 双栏
→ 左侧列表 + 右侧详情

这样做的价值不只针对 Duo。Split View、未来尺寸变化和其他可调整窗口环境都可以复用同一套布局逻辑。

优先让系统导航容器承担适配

Apple 明确把标准系统组件作为 Duo 适配的基础。对于 UIKit,常见的三个核心容器是:

  • UINavigationController
  • UITabBarController
  • UISplitViewController

系统导航、分栏和标签栏容器在不同可用空间中的适配关系

例如一个列表详情页面,在紧凑空间下可以折叠成单栏;内屏空间足够时,UISplitViewController 可以展开层级,而不是额外维护一套“Duo 专属导航”。

Apple 的 Human Interface Guidelines 也强调:设备展开以后可以展示更多一级信息,但应保持功能、状态和信息层级连续,不要因为折叠状态改变就把用户送到完全不同的产品结构里。

自定义 Tab Bar 是最需要重点检查的组件之一

系统 UITabBarController 能参与 iPhone Duo 的系统适配,但完全自己绘制的 Tab Bar 不会自动获得同样的行为。

传统底部自定义 Tab Bar 与 Duo 纵向侧边布局对比

如果 Tab Bar 由 UIView、UIVisualEffectView、UIButton、UIImageView 等自行组成,就需要自己决定:

  • 可用空间变化后是否重新排列;
  • 横向 Bar 是否需要转为纵向;
  • 中央按钮是否进入折叠区域;
  • 左右 Safe Area 不对称时如何调整;
  • 哪些低优先级操作进入 overflow。

工程上至少应该保证布局变化时能够重新计算,例如:

- (void)viewSafeAreaInsetsDidChange
{
    [super viewSafeAreaInsetsDidChange];
    [self updateCustomTabBarLayout];
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self updateCustomTabBarLayout];
}

这是具体工程建议,不是 Apple 强制要求所有项目必须使用这两个回调。Apple 的官方原则是:系统 Bar 优先使用标准容器,自定义 Bar 则要自行承担动态尺寸和特殊区域适配。

Safe Area 在 Duo 上可能是不对称的

传统代码很容易只关注:

self.view.safeAreaInsets.bottom

但 Apple 明确提醒,iPhone Duo 的 Safe Area 和 layout margins 在不同 display、pose 和系统 UI 下可能不对称。

外屏和展开内屏中的 Safe Area 可能具有不同的上下左右 Insets

因此应该把四个方向都看成动态值:

UIEdgeInsets insets = self.view.safeAreaInsets;

特别不要再默认:

left == right

当系统把 Toolbar、Tab Bar 或其他控件放到侧边时,leading / trailing 的可用空间就可能发生明显变化。

Reserved Regions:不要自己猜铰链坐标

Safe Area 并不能描述所有特殊区域,因此 UIKit 新增了 UIView.ReservedRegion。

Apple 当前文档定义了两类 Reserved Region:

  • occlusion:Dynamic Island、相机或窗口控件等遮挡内容的区域;
  • division:像折叠铰链一样,把内容空间分成两部分的区域。

Reserved Regions 用系统提供的 division region 标识真实折叠分割区域

所以不要采用这种思路:

屏幕宽度 ÷ 2
≈ 铰链位置

更正确的方式是读取系统提供的实际 Reserved Regions,再判断关键交互内容是否与其相交。

Apple 还说明,fold 对应的 division region 会随着设备姿态改变 active 状态;设备完全展开时,它可能变成 inactive。因此布局应该围绕“当前区域状态”变化,而不是围绕某个固定型号参数。

不是所有内容遇到折叠线都要移动

在 Design for iPhone Duo 中,Apple 特别区分了连续内容和关键交互控件。

文章、Feed、文档、列表等本来就能滚动的连续内容,并不需要为了 fold 整体位移。相反,Alert、Floating Action、媒体控制条等关键交互元素,更适合避开折叠曲面或根据姿态重新安排。

也就是说:

内容可以连续
关键交互要可见、可点、位置可预测

比“看到铰链就把整个页面切成两半”更符合 Apple 的设计方向。

不同 Pose 应该保持同一个任务连续

iPhone Duo 可以闭合、部分折叠或完全展开。Apple 并不要求为每一个姿态设计完全不同的界面,而是希望现有内容和控件根据空间自然变化。

闭合、部分折叠和完全展开时的不同布局示例

例如:

  • 闭合:外屏单栏;
  • 部分折叠:内容与控件按可用区域调整;
  • 完全展开:增加第二栏或更多上下文。

需要避免的是:用户只是把设备打开,App 就突然从当前任务跳成另一套 Dashboard 或完全不同的信息架构。

iOS 27.1 的 Arrangement 能力什么时候值得用

Apple 的 Duo 指南还介绍了新的 arrangement views,用 primary 和 secondary 两个区域,根据尺寸、比例和 Reserved Regions 动态组织内容。

它适合的不是所有页面,而是本来就存在明确“两块内容关系”的界面。例如:

  • 两个并排区域;
  • 主内容 + 覆盖控制层;
  • 部分折叠时需要把两块内容放到折叠线两侧的界面。

对于成熟项目,不需要为了 Duo 把现有 UISplitViewController 全部重写。只有页面本身确实符合 arrangement 模型时,再考虑采用新的 API。

用 Xcode 27.1 做什么测试

Apple 当前的 Get Ready for iPhone Duo 页面要求开发者使用 Xcode 27.1 beta 和 Duo Simulator 进行构建与测试。

建议至少覆盖:

外屏
- 竖屏
- 横屏

内屏
- 完全展开
- 部分折叠
- 不同方向

多任务
- Split View
- 动态 Resize

系统交互
- Keyboard
- Sheet
- Alert
- Context Menu
- Popover

自定义组件
- Custom Tab Bar
- Floating Button
- Player Controls
- Full-screen Content

辅助功能
- Dynamic Type
- RTL
- 长文本
- Dark Mode

测试时还要区分 App 自身问题与当前 beta Simulator 的限制,避免为了模拟器已知问题错误修改业务代码。

不做“Duo 专属界面”会影响 App Store 上架吗?

Apple 当前公开资料并没有要求每个 App 都必须提供一套单独的 iPhone Duo UI。

真正需要关注的是 App 在 Duo 上的实际行为:

  • 是否能动态 Resize;
  • 控件是否越界或被遮挡;
  • 是否正确处理 Safe Area;
  • 关键交互是否进入折叠区域;
  • Split View 是否正常;
  • 姿态变化后状态是否连续。

所以风险不是“没有 Duo 专属页面”,而是现有 App 在新的尺寸和姿态下出现真实兼容问题。

对现有 UIKit App,适配优先级可以这样排

P0
不能遮挡、越界、不可点击

P1
Size Classes / Safe Area / Split View 正常

P2
系统 Navigation / Tab Bar 正常自适应

P3
自定义 Bar / Floating UI 正确处理 Reserved Regions

P4
利用更大的内屏增加双栏和上下文

P5
进一步利用 Arrangement 与特殊 Pose 优化体验

先做到兼容,再利用新形态增强体验。

最后的判断:真正需要解决的是 Resizability

iPhone Duo 最重要的开发关键词不是“折叠屏专版”,而是 Resizability。

如果 UIKit App 已经做到:

  • 不依赖具体设备型号;
  • 不写死主布局尺寸;
  • 根据 Size Classes 组织界面;
  • 正确处理四个方向的 Safe Area;
  • 标准导航优先使用系统容器;
  • 复杂自定义 UI 能读取 Reserved Regions;
  • 动态 Resize 时不丢失状态;

那么 Duo 不需要变成一套新的 App 架构。

它只是把现代 iOS 本来就应该具备的动态布局能力真正放到了更复杂的设备形态上。

进一步检查:版本、布局稳定性与媒体尺寸

Duo 适配真正进入工程阶段以后,还有三类问题值得一起检查:使用 beta Xcode 和新 SDK 时,先把升级做成可回滚的独立动作,可参考开发工具版本锁定与升级边界;验证界面动态变化时,不只看“能显示”,也要检查布局跳动和稳定性,可参考布局偏移与可验证性能指标;如果页面包含大量图片或预览内容,提前保存媒体宽高比可以减少尺寸变化时的跳动,可参考响应式图库的尺寸占位实践。

这些文章不是 iPhone Duo 的官方规范,而是与“动态尺寸下保持界面稳定、升级可回滚”直接相关的工程方法。

Apple 官方参考资料

本文只把 Apple 明确公开的行为写成官方结论;具体 Objective-C 组织方式和自定义控件实现属于工程建议。

继续阅读

返回专题 →
Python 网格交易教程:手搓向量化回测引擎与 Docker 容器化实战Python 网格交易回测教程:用 NumPy/Pandas/Vectorbt 构建向量化实验,建模手续费、滑点和成交假设,做样本外验证,并用 Docker 固化运行环境。OpenAI Agents API vs Agents SDK vs Responses API:生产级 Agent 到底该把控制权交给谁?OpenAI 在 2026 年 9 月推出 Agents API 后,Responses API、Agents SDK、Agents API 三套能力很容易被混在一起。本文从 Agent Loop、状态、恢复、Tool Calling、Sandbox、多 Agent、成本、可移植性和业务控制权拆解三者的真实边界,并给出生产选型路径。Google ADK delete_session 为什么删不掉长期 Memory?2.8.0/2.9.0 实测Google ADK 调用 delete_session() 后,为什么 add_session_to_memory() 写入的长期记忆仍能被 search_memory() 搜到?本文用 2.8.0 与 2.9.0 做离线最小复现,并说明删除边界和生产处理方式。OpenAI 开始试验“按结果收费”:AI Agent 为什么可能不再只按 Token 计费?OpenAI CFO Sarah Friar 表示,公司正在企业 AI 中试验基于业务结果而非单纯使用量的定价。本文结合 OpenAI、Intercom、Salesforce、AWS 等一手资料,分析 AI Agent 定价为何从 Token/Usage 走向 Task、Outcome 与 ROI,以及独立开发者应如何设计成本、评测、计费和模型路由。

AI 工程周报

只发真正改变工程判断的变化、故障、实验和新资产。

评论与补充证据

参与讨论

问题、验证与勘误

登录后可发表评论。所有新评论先进入审核;审核期间仅评论者本人和管理员可见,通过后才公开。

登录评论 审核后公开
正在加载评论区…