这篇是「iPhone Duo 六支苹果官方 Tech Talks 视频」系列的第二篇,前一篇与后续内容分别讨论设计原则、导航栏、自适应布局、多屏和相机。本篇先从工程准备开始,说明如何用新 SDK、Xcode 和 Device Hub 检查现有应用,再把布局调整到能应对外屏、内屏、旋转、折叠和分屏视图多任务模式。

先用最新 SDK 建置

结论很简单:旧应用也能在 iPhone Duo 上运行,但用越新的 SDK 构建,应用能使用的屏幕空间越多。

即使应用不是用 iOS 27 SDK 构建的,闭合状态下也可以正常运行。系统会让应用利用状态栏和摄像头左侧的屏幕空间;设备展开后,应用仍会呈现熟悉的大小和宽高比。这意味着,现有项目不必等到大改版后才能测试 iPhone Duo。

如果项目已经采用 iOS 27 SDK,屏幕利用率会再提高:应用可以延伸到内屏状态栏区域的左侧。用 iOS 27.1 SDK 构建时,应用会进一步延伸至屏幕边缘,标准导航和工具栏按钮则会垂直排列在状态栏下方。

不同 SDK 构建的应用,在内屏上能利用的范围不同

这几档行为不是靠判断机型来切换的。先更新 SDK,再观察系统提供的默认布局,通常比在项目里增加设备判断更稳妥。

在 Xcode 和 Device Hub 中开始

建议直接使用 Xcode 27.1。创建或打开项目后,在 Device Hub 中选择 iPhone Duo 模拟器运行应用。

模拟器底部提供姿态控制。你可以打开、关闭、旋转或折叠 iPhone Duo,然后逐一观察布局变化。这里要看的不只是应用能否启动,还包括导航、工具栏、按钮和主要内容在每种姿态下是否仍然可见、可操作。

Device Hub 里的 iPhone Duo 模拟器

第一次全屏运行时发现问题很正常。旧项目常把固定宽高、固定方向或固定边距当成默认前提;内屏把可用空间放大后,这些假设就会暴露出来。

用灵活布局处理尺寸变化

iPhone Duo 要求应用在展开、收起、旋转和折叠之间重新调整大小。适配思路与普通 iPhone 的尺寸变化相同:不要根据某个机型猜测屏幕尺寸,也不要根据界面惯例猜测设备能力;让布局根据实际可用空间决定展示方式。

iPhone 应用早就需要应对新屏幕尺寸、不同屏幕形状,以及灵动岛这样的特殊区域。iPhone Duo 只是把这件事推得更远:同一个应用会在更多尺寸类边界之间变化。即便如此,它仍然是一款 iPhone 应用,布局不应该把某一块固定屏幕当成唯一目标。

例如,Podcasts 这类内容应用,在空间较小时可以优先显示当前内容,在空间较大时显示侧边栏和更多列表项。这里的判断依据应该是可用空间,而不是“这是某某型号”。

同一套布局要应付展开、收起、旋转和折叠

用尺寸类区分布局

尺寸类与对应方向上可用空间的关系比较宽松。它表达的是应用在当前空间里应提供哪一种用户体验,而不是某个具体设备的标签。

SwiftUI 使用 environment,UIKit 使用 trait collection。外屏的行为接近其他 iPhone:竖屏时采用常规垂直尺寸类和紧凑型水平尺寸类;横屏时采用紧凑型垂直和水平尺寸类。

内屏的可用空间更大,允许界面同时显示更多内容,例如侧边栏,因此采用常规水平和垂直尺寸类。这个差异正适合用来切换小布局与大布局。

外屏的界面方向行为与其他 iPhone 相同。内屏则不同,它不会遵循应用支持的界面方向设置。不要在布局决策中检查界面方向,改用尺寸类。用户把 iPhone Duo 像帐篷一样平放时,横向布局也会更有用;尺寸类能比方向判断更准确地表达这一点。

SwiftUI 用 environment 读取尺寸类

避免引用主屏幕

在双屏设备上,代码里引用主屏幕会产生歧义,这种用法也将在未来版本中被废弃。能不引用屏幕,就不要引用。

优先采用更局部的概念:SwiftUI 使用 environment,UIKit 使用 trait collection,也可以使用场景的边界。如果确实需要访问屏幕,应通过窗口场景动态访问,而不是拿一个全局主屏幕当作尺寸来源。

这条规则对计算器、吉他 App 或提词器都适用。比如提词器需要知道当前内容区域的宽度,应读取当前场景的布局空间;不能把外屏宽度缓存下来,再拿它去推算内屏的字号和控件位置。

如果 UI 需要贴合屏幕角落,还应使用 iOS 26 引入、并已更新以适配 iPhone Duo 屏幕形状的同心度 API。SwiftUI 使用 ConcentricRectangle,UIKit 使用 UICornerConfiguration。它们用于处理屏幕角落的形状,不必自己猜测圆角尺寸。

项目若使用 UIRequiresFullScreen,也不会因此停止调整大小。iPhone Duo 打开或关闭时,应用仍会改变尺寸;系统会尊重应用支持的界面方向,但内屏上仍可能发生缩放,包括分屏视图多任务模式。

采用标准导航模式

要让界面跨姿态变化,优先使用标准导航。SwiftUI 的 NavigationSplitView 与 UIKit 的 UISplitViewController 都具备自适应能力。

闭合状态下,导航栏会折叠成单列堆叠式导航。打开后,导航栏可以以平铺和叠加的形式显示。应用无需为每个姿态维护一套完全独立的导航树,系统会根据空间重新安排层级。

标签页同样如此。SwiftUI 的 TabView 与 UIKit 的 UITabBarController 能适应所有使用姿态。默认情况下,标签页会同时出现在内屏和外屏上,并在合适时垂直排列。内屏空间充足时,可以把标签页放到侧边栏:SwiftUI 将默认标签栏位置设置为侧边栏,UIKit 将首选位置设置为侧边栏。

即使声明了 UIRequiresFullScreen,应用仍会调整大小

弹出视图也会随姿态变化。外屏上,弹出视图中的按钮可以垂直排列;内屏上,弹出视图会居中显示。弹出框、上下文菜单和提示框也会随屏幕姿态调整。

正确处理安全区域

导航栏、工具栏和标签栏会布局在安全区域之外,并自动避开状态栏、摄像头等系统 UI 和硬件区域。水平条会提供顶部和底部内边距,垂直条会提供首行和尾行内边距。

交互控件和其他前景内容放在安全区域内。SwiftUI 默认会把内容放在安全区域内;UIKit 手动布局时,参考视图的安全区域内边距,或用自动布局把视图约束到安全区域布局指南。

背景可以越过安全区域。全出血图片等背景元素可以填满可用空间,并延伸到工具栏和侧边栏之后。SwiftUI 使用 ignoresSafeArea,UIKit 使用视图的 bounds。

标准导航容器在展开后自动呈现多列

不要假设左右或上下内边距相等。安全区域和布局边距通常是不对称的,iPhone Duo 上尤其明显。横屏和分屏视图多任务模式下,垂直按钮可能出现在左侧,前景内容就需要分别处理每一侧的距离。

用 Device Hub 在内屏预览分屏视图多任务模式:拖动底部的主屏幕指示器,把应用放到屏幕一侧;出现放置区域后,再把另一个应用拖到另一侧。垂直布局内容可能出现在应用的任一侧,这正是固定对称边距容易出错的地方。

用 ReservedRegion 处理自定义界面

iOS 27.1 引入了一个新 API,让自定义 UI 在不与系统 UI 冲突的前提下利用更多屏幕空间。

SwiftUI 使用 ReservedRegion,UIKit 使用 UIViewReservedRegion。它们可以把 UI 元素安全地放在安全区域之外,同时告诉系统哪些位置需要保留。自定义状态栏或全屏 UI 都可以考虑这种方式;布局越接近系统区域,越应该明确声明占用关系,而不是直接覆盖。

背景可以越过安全区域,交互内容要留在区域内

普通界面优先交给标准状态栏和标准控件处理。只有复杂的自定义布局需要更多控制时,再考虑 ReservedRegion。这样能减少自己维护每一种姿态的工作量。

最后检查一遍

Xcode 27.1 里,原来的应用现代化技能更名为 App Resizability,现在支持 SwiftUI 和 iPhone Duo。它可以用来检查项目是否遵循这些自适应布局实践。

ReservedRegion 与 UIViewReservedRegion 为自定义界面预留区域

适配可以按下面的顺序进行:

  • 用 Xcode 27.1 和 iPhone Duo 模拟器启动现有应用,检查四种姿态。
  • 用 environment 或 trait collection 根据可用空间切换布局,不按机型和方向写固定判断。
  • 移除主屏幕引用,改用局部环境、特征集合、场景边界或窗口场景。
  • 优先采用 NavigationSplitView、UISplitViewController、TabView 和 UITabBarController 等标准导航。
  • 把交互内容放进安全区域,测试非对称边距和分屏视图;复杂自定义 UI 再评估 ReservedRegion 或 UIViewReservedRegion。

iPhone Duo 适配的起点不是重画一套界面,而是把尺寸、方向和屏幕引用这些假设交还给系统。先在 Device Hub 里把姿态变化跑一遍,再根据尺寸类、安全区域和场景边界修正布局,通常能更快找到真正需要改的地方。

系列文章

这套教程一共六篇,对应苹果官方的六支 Tech Talks 视频: