症状:界面在某个固定宽度下看起来正常,一旦窗口变化、横屏或键盘出现,按钮被裁切、表单跳回顶部,甚至编辑内容消失。
最快解法:现在就做苹果折叠 iPhone 适配,不要等待官宣尺寸;移除固定屏幕假设,依靠安全区、尺寸特征和自适应布局,并把状态恢复当成独立验收项。
这篇适合你:
- 界面中存在固定宽高、绝对坐标或按设备型号分支的 iOS 开发者;
- 需要让复杂表单、视频、编辑器适应尺寸变化的产品与设计团队;
- 正在建立折叠形态兼容性用例的移动 QA、发布和验收负责人。
最后更新于 2026 年 9 月 5 日。 本文只依据苹果已公开的 Human Interface Guidelines、UIKit 与 SwiftUI 文档复核方法;截至该日期,苹果没有确认折叠 iPhone 的产品名称、屏幕形态或专用开发接口。相关传闻只作为适配背景,不用于推导分辨率、铰链位置或尺寸分支。
先把“固定屏幕”从代码审查中清掉
折叠设备真正容易击穿的,不是某一个控件的边距,而是团队把“当前设备尺寸”误当成“产品永远存在的画布”。典型问题包括:
- 使用
UIScreen.main.bounds推导所有子视图宽度; - 用
frame(width:height:)或绝对坐标摆放操作按钮; - 根据机型名称、截图像素或某个宽度阈值切换整套页面;
- 默认导航栏、底部工具栏和浮层永远占据相同高度;
- 把横屏当成特殊页面,而不是同一任务在不同可用空间中的表现。
苹果公开的布局指南要求界面适应不同屏幕尺寸、方向、Dynamic Type、系统特性和可调整窗口,并建议使用 SwiftUI 或 Auto Layout 响应环境变化。尺寸特征的本质是描述当前可用环境,而不是预测未来设备的具体物理尺寸。(developer.apple.com)
先在代码库中建立一次“固定尺寸扫描”,比立刻制作折叠设备设计稿更有价值:
| 检查对象 | 高风险写法 | 更稳妥的替代方案 |
|---|---|---|
| 屏幕宽度 | 直接读取全局屏幕边界 | 读取容器实际可用空间 |
| 控件位置 | 绝对坐标、固定中心点 | Auto Layout 约束、Stack、Grid 或自定义 Layout |
| 页面分栏 | 按设备型号切换 | 根据尺寸特征和内容优先级切换 |
| 全屏内容 | 忽略顶部、底部系统区域 | 使用 safe area 与容器边界 |
| 状态保存 | 状态挂在被销毁的视图上 | 数据模型、SceneStorage 或 UIKit 状态恢复 |
SwiftUI 先处理容器,再处理控件
如果你使用 SwiftUI,不要一开始就为“展开态”和“折叠态”复制两棵完全不同的视图树。优先让同一组内容根据提议尺寸选择合适结构。
ViewThatFits 可以按照声明顺序选择第一个能够放入当前空间的子视图,适合处理“横向并列信息放不下时退化为纵向或单控件”的情况。AnyLayout 则可以在改变布局容器类型时尽量保留子视图状态,适合在 HStackLayout 与 VStackLayout 之间切换。(developer.apple.com)
例如,一个编辑器工具栏可以按以下优先级组织:
- 宽阔空间:标题、格式工具、协作状态和保存按钮同排显示;
- 中等空间:保留标题与主要操作,次要工具进入菜单;
- 紧凑空间:只保留当前任务必需的操作,其余通过底部工具栏或菜单访问。
这样做的关键不是“缩小所有元素”,而是让信息结构发生可预测的变化。苹果的布局指南也强调,当完整布局无法容纳时,应优先隐藏次要列或辅助信息,而不是让所有内容继续挤压。(developer.apple.com)
UIKit 重点检查 trait 与容器边界
UIKit 团队应重点查看 traitCollection、viewWillTransition(to:with:)、容器控制器和 Auto Layout 约束是否承担了真正的布局职责。不要在 viewDidLoad 中依据首次读取到的宽度决定永久结构,也不要把 view.frame 当成后续所有子视图的基准。
如果页面在尺寸变化后需要从单列切换到双列,建议让父容器决定列结构,让子控制器只负责自己的内容。这样尺寸变化时可以重新安排控制器,而不会把导航状态、编辑模型和网络请求全部绑定到一次视图重建上。
按安全区重新检查裁切与触控区域
折叠 iPhone 适配中最容易被传闻带偏的部分,是提前猜测铰链、开孔或屏幕分割区域,然后在界面中预留固定空白。这个做法既无法覆盖真实系统行为,也会浪费普通设备上的可用空间。
安全区才是今天可以运行、可以测试的依据。苹果将 safe area 定义为不被工具栏、标签栏或其他窗口内容遮挡的区域,并明确指出系统会在系统栏尺寸变化时更新安全区。UIKit 可以通过 safeAreaLayoutGuide、safeAreaInsets 和 viewSafeAreaInsetsDidChange() 重新计算内容位置。(developer.apple.com)
按照以下顺序排查:
- 导航栏下方的标题、搜索框是否被内容覆盖;
- 底部提交、购买、播放和删除按钮是否贴近系统手势区域;
- 全屏视频、相机预览和地图是否错误地把安全区当成黑边;
- 浮层关闭按钮是否在横竖屏变化后落到不可触控区域;
- 自定义
additionalSafeAreaInsets是否只在特定页面设置,却没有在返回时恢复。
苹果 HIG 同时建议交互控件保留足够的触控面积:iOS 和 iPadOS 控件的默认尺寸为 44 × 44 pt,最低尺寸为 28 × 28 pt。这不是折叠设备专属规则,但它能帮助你发现“展开后控件看似变多,实际变得难以点击”的问题。(developer.apple.com)
经验提醒: 不要把“屏幕中间可能有铰链”翻译成一个固定的
padding。如果未来系统提供专用窗口或显示区域信息,应优先消费系统提供的环境数据;在此之前,使用安全区和实际容器尺寸即可。
用内容优先级处理紧凑与宽阔布局
可变尺寸 UI 的失败案例通常来自等比放大:列表行变宽了,但标题、筛选条件和批量操作仍然挤在同一行;编辑器增加了空白,却没有为预览、属性面板和撤销操作重新分配空间。
你可以先为每个核心页面写一份内容优先级表:
| 页面类型 | 紧凑空间保留 | 宽阔空间增加 | 不建议做法 |
|---|---|---|---|
| 列表 | 标题、状态、主操作 | 预览列、筛选栏、批量操作 | 所有字段等比例拉宽 |
| 详情 | 核心字段、编辑入口 | 相关信息、历史记录、辅助面板 | 依赖横向滚动隐藏字段 |
| 表单 | 当前步骤、保存、错误提示 | 分组说明、实时预览、辅助建议 | 缩小字号解决拥挤 |
| 视频 | 播放、进度、音量 | 章节、评论、播放列表 | 将控制条固定在屏幕底部 |
| 编辑器 | 文本与撤销 | 侧栏、预览、属性检查器 | 用设备型号决定布局 |
尺寸特征可以用于选择结构,但不要让每个阈值都对应一套页面。设计评审时,产品经理应先回答“用户在窄空间里最不能失去什么”,再决定哪些内容折叠、延后或移入菜单。
对于 SwiftUI,可以把布局选择集中在一个适配容器中,避免业务子视图各自判断宽度。对于 UIKit,则可以由父级容器根据 traitCollection 和实际边界安排子控制器,子页面只暴露内容与操作,不直接猜测设备形态。
把状态恢复从视图生命周期中拆出来
尺寸变化、横竖屏切换和后台恢复之所以经常同时暴露问题,是因为团队把“页面当前长什么样”和“用户进行到哪一步”写在了同一层。
以下内容都不应只存在于某个视图实例的临时属性中:
- 正在编辑但尚未提交的文本;
- 当前选中的项目、筛选条件和排序方式;
- 列表或阅读页的滚动位置;
- 视频或音频的播放进度;
- 导航栈中的当前路径;
- 多步骤表单已经完成的步骤;
- 相机、上传或导出任务的阶段。
SwiftUI 的 @State 适合管理视图局部的临时状态,不应被当作持久化存储。对于轻量、与某个场景绑定的值,可以使用 @SceneStorage;苹果同时提醒,SceneStorage 不保证具体保存时机,不适合大型模型或敏感数据。(developer.apple.com)
UIKit 场景则应使用 NSUserActivity 和场景级状态恢复机制,保存足够重建界面的信息。苹果文档明确说明,iOS 13 及以后,基于场景的应用可以为每个窗口场景保存状态;恢复内容应包括重新创建界面和回到用户当前任务所需的数据。(developer.apple.com)
建议按这 6 步落地:
- 列出所有用户可感知的任务状态,而不是只列页面名称;
- 为每项状态标记“可丢失”“必须恢复”或“必须写入业务模型”;
- 将状态放到视图树之外的模型、路由或场景存储层;
- 在尺寸变化前后对比状态快照,确认布局重组没有重置数据;
- 模拟后台、系统终止和重新启动,检查能否回到合理任务点;
- 对未保存内容给出明确提示,不要用静默重建掩盖数据丢失。
覆盖键盘、媒体和后台切换的组合故障
单独测试横屏通常发现不了真实问题。更接近用户现场的用例是:用户正在编辑表单,键盘已经弹出,视频或相机任务仍在运行,随后窗口尺寸变化或应用进入后台。
UIKit 的键盘通知使用屏幕坐标系,而不是始终等同于当前视图坐标系;在分屏、浮动窗口或其他非全屏环境中,必须先转换坐标,再计算内容需要避让的区域。(developer.apple.com)
至少执行以下组合测试:
- 输入框获得焦点 → 键盘出现 → 横竖屏切换;
- 键盘出现 → 页面进入后台 → 返回后继续编辑;
- 视频播放 → 尺寸变化 → 控制条重新布局;
- 相机调用 → 权限弹窗 → 页面恢复;
- 上传或导出进行中 → 系统挂起 → 回到页面;
- 正在滚动列表 → 结构从单列切换为双列;
- 编辑内容未保存 → 页面重建 → 检查草稿与导航路径。
SwiftUI 团队可以观察 scenePhase,在场景进入后台时保存轻量状态、暂停计时器或释放不必要资源。苹果文档指出,场景可能处于 active、inactive 或 background 状态,而且进入后台后应用可能很快被终止,因此不能把后台事件当成永远可靠的长时间执行点。(developer.apple.com)
没有真机时,先建立可重复的验收矩阵
没有折叠 iPhone 真机,并不意味着只能等待。你现在可以使用已有不同尺寸设备、模拟器、可调整窗口和自动化截图测试,先发现大多数布局与状态问题;真实设备出现后,再补验铰链形态、特殊触控区域、性能和系统专属交互。
建议把验收拆成三层:
第一层:静态布局审查
- 搜索固定宽高、绝对坐标和设备型号分支;
- 检查 Auto Layout 是否存在冲突、压缩或优先级反转;
- 检查文本放大、长本地化字符串和辅助功能尺寸;
- 检查按钮是否达到足够触控面积;
- 检查背景可以延伸,但关键内容没有越过安全区。
第二层:窗口变化测试
- 逐步扩大和缩小可用空间;
- 在紧凑、中等、宽阔三类布局之间反复切换;
- 记录结构变化是否稳定,是否出现闪烁、重复请求或导航重置;
- 对表单、编辑器、媒体和列表分别保存截图基线。
第三层:进程与任务恢复测试
- 在编辑、播放、上传和相机调用期间进入后台;
- 终止进程后重新打开;
- 对比编辑文本、滚动位置、筛选条件、播放进度和导航路径;
- 验证恢复失败时是否有明确降级,而不是显示空白页面。
自动化截图不需要知道未来折叠设备的真实屏幕尺寸。它只需要向界面提供不同的容器边界,并观察内容是否完整、操作是否可达、状态是否保持。苹果的 ViewThatFits、自定义 Layout 和现有窗口尺寸机制,已经足够支持这类前置回归。(developer.apple.com)
如果团队需要并行运行多个 macOS 测试节点或远程构建环境,可以先查看 Macstripe 帮助中心,把模拟器、截图回归和日志归档流程固定下来;等苹果正式公布新设备与 SDK 后,再依据官方接口补充专属用例,而不是提前维护一套传闻驱动的页面分支。
在今天就能执行的苹果折叠 iPhone 适配中,真正值得投入的不是猜测屏幕会折在哪里,而是清理固定尺寸假设、让安全区成为唯一可信边界、把内容优先级写进布局决策,并验证场景中断后的任务状态。自购多台实体设备适合长期实验室和高频回归,但成本、设备排队、系统版本维护和自动化接入都会增加;单纯依赖本地某一台 iPhone,又无法覆盖可变窗口与进程恢复。若你需要临时并行的 Mac 测试环境,或想把模拟器、截图和构建任务拆到远程节点,可以再根据团队的并发量查看 Macstripe 的 Mac 配置方案,先完成可变尺寸回归,再决定是否值得等待折叠真机覆盖。