外屏、展开态、悬停态三种形态与一个布尔适配标签的失真

一、这条新闻里能拿走的东西,是那句”不只是能运行”

10 月 22 日苹果发博文,宣布将在 App Store 引入”Made for iPhone Duo”标志,用来标识已经适配其首款折叠机型的应用和游戏;据公开报道,这个标识在 10 月 23 日、也就是 iPhone Duo 在部分地区开售当天出现在相关应用的产品页面上。苹果对它的说明里有一句值得单独摘出来(同样据公开报道):拿到标识代表的不只是”能在大屏上运行”,还包括把内外双屏、更大的显示区域和折叠形态真正用起来。

我们要讨论的就是这半句区分。它把三件平时被混着说的事摆开了:

  1. 能运行:进程不崩、页面出得来、用到的能力没有被裁掉。绝大多数应用在新硬件上架第一天就满足这一条,所以它不需要声明。
  2. 布局正确:展开、合起、半折叠三种尺寸下不裁切、不重叠、不误触,可读性达到基线。这一层要改样式和布局判定,工作量可以估。
  3. 交互充分利用:新形态换来的是并行视野和姿态分工,界面用它承载了什么语义。分屏导航、上半屏预览下半屏控制这类才属于第 3 层,多数应用从来没走到这里。

一个布尔标签必然把三层压成一件,这是声明机制的固有失真,不是谁执行得不认真。拆开看有四条:层次失真——标签不说明它落在第几层;时间失真——验证针对某个版本的某些行为,标签却不记版本、不记验证日期,第二次迭代后没人重跑,声明还在;范围失真——产品页只有一个标志,用户会读成”这台机器上哪儿都适配了”,但适配永远是局部命题,清单页过了不代表某个二级流程的长表单测过;不可证伪——没有撤回与记录机制时,”已经适配”和”曾经适配”在外部看起来一模一样。

所以在我们眼里,一条能被当作证据的兼容声明必须带三件东西:声明者是谁、断言范围具体到哪个功能哪一版、有效期到什么时候。缺任何一件,标签就从工程证据退化成营销位。标志的价值也是真的:它把已经做完的验证变成用户可检索的信号,替用户省掉”到底有没有人试过”那次搜索。失真的补法在声明方自己手里,平台不会替你把层次和范围写出来。

二、适配工作真正分几层:改什么、回归到哪、谁签字

断点、宽高比、安全区那一层的技术清单,站内《手机屏幕回到多形态时代:适配要重算的不只是断点》已经写过一遍,这里不重开那张表。要问的是另一个问题:每一层的完成度由谁签字,签完之后回归范围是什么。因为打标真正消耗的是这两样东西,而不是代码行数。

层级 需要改什么 回归测试范围 谁签字
尺寸与布局分支 不假设固定比例,按容器而不是机型分支 全部页面的极值尺寸截图比对 前端负责人
运行时尺寸切换 折叠与展开、内外屏切换时场景不重建、状态自持 表单、播放、长列表三条关键流程的状态断言 客户端与测试共同
半折叠姿态分工 上下屏的角色分配是新设计,不是把同一套控件重排 悬停态交互走查、误触与遮挡 产品与设计
摄像头与传感器 内外摄切换、取景预览的坐标换算 取景与扫码全流程,含旋转与遮挡 客户端
内容重排策略 哪些区域该并排、哪些该隐藏 同一份数据在不同栏位下不丢信息 产品负责人

最后一行是唯一能被用户直接感知的判断,也是最容易被跳过的一行。高德公开的适配方案是分屏导航:左侧车道级导航、右侧常规地图的前方路线与路况,两种视野并排,并支持随内外屏切换。它不是”把一屏切成两半”——车道级指引和路况概览分属两个抽象层级,并置之后各承担不同时长的决策,秒级的变道判断与分钟级的路线判断互不打扰。被适配的是这套分工,切屏时要保住的也是这套分工。反面做法我们见得多:列表左右各铺一遍、字号缩到塞得下,第 3 层什么都没做,对外一样说”已适配折叠屏”。

第 2 行和第 3 行的区别也要说清:改样式是编译期的事,改姿态分工是产品规则的事。半折叠时上屏放预览、下屏放控制条,这条规则一旦写进交互就得有”合起之后控制条去哪”的配套答案,否则会出现控制条悬在半屏之外这种谁都没设计过的状态——它不靠加断点解决,只能靠把规则写全。

三、”切屏不丢状态”是验收点,不是特性

据公开报道,苹果在开发工具侧补了折叠形态的模拟器和尺寸变化相关的回调,让应用能在展开、半折叠和内外屏切换时自行调整布局。工具解决的是”能测”,不解决”测什么”。而这一层最常见的故障原因只有一个:尺寸变化被当成一次冷启动。生命周期里视图控制器或活动被整个拆掉重搭,样式跟着重建走一遍,看起来正常,代价是网络请求重发、视频从起点播、表单清空、滚动位置归零。用户感知到的是”我的东西没了”,而且恰好发生在他填到一半的时候。

下面是我们会直接抄进测试计划的用例写法。核心要求是断言落在数据上,不是落在截图上。

  1. 锚点断言。进入目标页面,向一个输入框写入可辨识的值(形如 probe-<时间戳>),把列表滚到中部并记录偏移。执行折叠↔展开十次,每次回到同一页面断言三件事:页面标识未变、输入值未丢、滚动偏移在约定误差内。任何一次断到空值即整条用例失败,不接受”偶尔能过”。
  2. 飞行中切屏。在弱网模拟下把带宽压到最低档,发起一次分页加载,请求未完成时切屏。断言请求没有被重发(看抓包条数与请求序号),返回后结果落在原位而不是回到顶部。这条最狠,因为场景重建的副作用最先体现在重发上,而重发在有副作用的接口上等于重复提交。
  3. 播放与录制。进度非零时切屏,断言时间轴继续;录音或录屏进行中也各跑一次。这两条链路的失败代价是素材丢失,事后无法重试,所以优先级高于所有界面问题。
  4. 四段姿态往返。展开→半折叠→合起→展开连走一遍,断言上下屏角色分配回到原状、没有残留控件,半折叠引入的分界线在合起后完全消失。
  5. 弹窗与键盘叠加。对话框打开且软键盘弹出时切屏,断言两者状态不互吞。这一格最容易造出”提交按钮点不到”的不可用状态。
  6. 时长与泄漏。上述用例连续执行二十分钟,同时看内存与句柄曲线。切屏路径上的泄漏表现为阶梯式上涨,头两次切换看不出来。

这六条里前两条我们当成底线:任何声称”随内外屏切换不丢状态”的功能,至少要能交出这两条的执行记录,否则这句话在我们的文档里只能写成”切屏后布局自适应”——那是一件弱得多的事,也是第 1 层能承诺的上限。

四、打了标之后:承诺的撤回成本比晚打高

标签一旦出现,用户就会把它当承诺读,”没打标”和”体验差”两件事都会被归责到开发者头上。这是声明机制的必然代价,不是平台刁难。我们的立场只有一句:宁可晚打,不虚标。落到操作上四条:

  1. 打标范围等于已验证范围,不扩写。做不到整站覆盖就在文档里写明”清单与详情已验证、某二级流程未验证”,而不是打一个总标签赌用户不走到那一页。
  2. 打标自带内部快照。当时打包的版本、跑过的用例编号、失败项与降级说明留一份档。外部看到的是一个标志,被追问时我们要拿得出当时究竟测到哪一层。
  3. 负向清单排在正向清单之前。把不支持的具体项逐条列出来,这条与站内一贯的做法相同——“能做什么”的清单客户会当成参考,”不做什么”的清单才会被当成依据。
  4. 虚标的回撤成本远高于晚打。撤下一个标志在外部通常会被读成出过事故,而晚打的成本只是这段时间里没有差异。所以只要第 3 层还没做完,就不要用第 1 层的完成度去声明第 3 层的结论。

第二点在洹拓科技的方案评审里是硬性材料:任何”已支持”三个字进对外文档之前,必须能指出它对应哪条用例的哪一次执行记录。指不出就改写成”该场景未测试”或者”仅验证到某种尺寸”。这条规矩看起来啰嗦,实际省下的是事后自证的成本。

五、搬回自研产品:把”支持”写成三态矩阵

多数自研 Web 与 SaaS 产品没有应用商店那样的标志位可拿,但要回答的却是同一个问题——客户采购表里的”支不支持”。我们的做法是把它做成文档里的一张矩阵,而不是文档末尾一句”适配主流设备”。行是形态,列是关键功能,单元格只用三个状态词:已验证、布局可用、未测试。

形态与功能 登录鉴权 主查询 长表单填报 文件上传 在线预览
直板窄屏 已验证 已验证 已验证 已验证 布局可用
折叠展开态 已验证 已验证 未测试 布局可用 未测试
半折叠悬停 未测试 未测试 未测试 未测试 未测试
平板横屏 已验证 已验证 布局可用 已验证 已验证
桌面窄窗分屏 已验证 布局可用 未测试 未测试 未测试

三个状态词的口径必须写在表格上方,否则这张表照样会被读错:

  • 已验证:第三节那套状态断言用例跑过,有留档,含失败项记录;
  • 布局可用:不裁切、可滚动、能提交,但没有做状态自持验证,切屏或改窗口后不保证输入不丢;
  • 未测试:既不是支持也不是不支持,是没有证据。

第三个词最要紧。把”未测试”写成”不支持”是过度自谦,会让自己少卖一块能力;写成”支持”就是虚标,出事时要连别人一起赔。把这两类冲动都用一个中立词挡住,是我们认为三态比二态好用的唯一理由:二态矩阵逼着填表的人猜,三态矩阵允许他承认没做。矩阵之外还要配一行口径说明——覆盖的浏览器主版本区间、最小逻辑宽度、系统字号档位,以及这张表的复核周期;复核周期一到就得重跑,否则它又会退化成第二节里那个”曾经适配”。

六、判断

这件事值得搬进我们日常交付的部分,不是”苹果发了个标志”,而是它把一个一直含糊的说法拆成了三层,并让开发者为声明负责。对用户,标签机制省掉一次搜索;对开发者,它把承诺从上线后挪到了打标前。所以我们签字的写法是三态矩阵加带版本与日期的验证留档,二态(能用、不能用)不是——二态矩阵里的每一个”能用”,都会在半年后变成一次没有记录的争论。

反过来,什么条件下这套做法不成立:如果团队连第三节前两条用例都维护不了——没有弱网模拟、没有可断言的页面标识、切屏后拿不回输入值——那三态矩阵只会填成一堆”未测试”,看起来诚实但给不出任何决策信息。这种时候正确的动作不是降级回二态,而是先把切屏用例的两条底线建起来;一条状态断言用例的成本,比一次”你们不是说不支持吗”的返工便宜得多。形态碎片化这件事不会自己收敛,能收敛的只有我们描述它的方式。