HarmonyOS 7 平行视界 EasyGo 实战:配置文件接入应用内分屏,1:2/2:1 随意切

0 阅读5分钟

本文基于 HarmonyOS 7(API 26)官方《平行视界》能力介绍与开发指导整理。文中代码是为说明问题自写的完整示例,不是官方示例的搬运;配置文件字段名、枚举值等事实性信息均标注官方出处,未能逐字核实的指向写法已注明"以官方文档为准";涉及真机表现的部分以真机实测为准,未做任何实测数据编造。


HarmonyOS 7 平行视界 EasyGo 实战

引子:折叠屏展开的那一刻,你的应用在"整页跳"

V哥有个习惯,拿到新折叠屏先装自己团队的电商 Demo。展开态下点一个商品,整页跳转;再点推荐商品,又整页跳转。十二英寸的屏幕,利用率不到一半,旁边全是黑边和留白。同事说了句扎心的:"这应用是把平板当大号手机用。"

传统解法是重写导航:把 Router 迁到 Navigation、把页面塞进双分栏布局、把状态同步逻辑推倒重来。对多数业务团队来说,这是一场伤筋动骨的重构。

HarmonyOS 7(API 26)把另一条路铺好了:平行视界 EasyGo 能力升级,开发者不改业务代码,写一份配置文件就能让应用在大屏上以左右双页的方式运行,路由模式、分栏比例、分割线样式全部可配(官方新能力一览)。这期V哥把它拆开讲:机制、配置、路由模式、比例与分割线、应用内分屏,最后给一份"该不该用平行视界"的选型判断。


一、先摆正定位:平行视界是系统级兜底,不是新框架

官方的定义很克制(平行视界能力介绍):

平行视界是一种针对大屏设备(折叠屏、平板)开发的系统级应用显示技术。它打破了传统移动应用只能在单一页面显示的局限,允许同一个应用在屏幕上同时开启两个页面,实现"一级页面左侧显示,二级页面右侧显示"的布局模式。

V哥从这段话里读出三个重点:

重点意思对开发者的直接影响
系统级分栏由系统按路由栈自动完成,不进你的页面代码老业务零改动,只写配置
兼容方案官方原话:针对"未适配分栏布局"场景的系统兜底方案定位是快速接入,不是精细定制
自配置从 API 23 起SDK 6.1.0(23) 即支持开发者自配置;路由模式、比例、分割线等为 API 26 新增老版本只能吃默认 1:1,7.0 才有完整的"随意切"

第三条要特别标注:路由模式、分栏比例拖拽、分割线颜色这些 7.0 的新能力,需升级至 HarmonyOS 7 并以实际支持机型为准,具体表现以真机实测为准。

还有一条硬边界:自由多窗模式下,暂不支持平行视界(官方说明,针对 tablet 设备配置项)。做窗口化场景的应用要先确认自己的主战场。


二、接入三步:一份 JSON、一行注册、应用级生效

官方把物理形态规定得很简单(平行视界开发指导):在 profile 目录下创建配置文件(官方示例名 easy_go.json,可自行命名),在 module.json5 中添加 easyGo 字段指向它。当前仅支持在 entry 模块下配置,配置后应用级生效。指向写法的细节以官方文档"开发步骤"一节为准,这里写结构示意:

{
  "module": {
    // V哥注:easyGo 字段指向 profile 目录下的 easy_go.json(文件名可自行命名),
    // 具体指向写法以官方文档《平行视界》开发指导"开发步骤"一节为准
    "easyGo": "$profile:easy_go"
  }
}

easy_go.json 是标准的两层 JSON(字段名均已按官方文档核实):

{
  "common": {
    "displayModeOptions": {
      // 长方形宽屏窗口(>=600vp 且宽/高 > 1.2):走 Navigation 分栏
      "wideWindowMode": "navigationSplit",
      // 方形宽屏窗口(>=600vp 且高/宽、宽/高均 <= 1.2):同上
      "squareWindowMode": "navigationSplit",
      "navigationSplitOptions": {
        "homePage": "navBar",                 // Navigation 首页做主页;用 NavDestination 做主页则配其 name
        "relatedPage": "CategoryPage",        // 启动关联页:冷启动直接进列表
        "mode": 0,                            // 0=购物模式(左右推挤),1=导航模式(固定覆盖),默认 1
        "wideSplit":   { "ratio": "1 | 2" },  // 长方形窗口默认 1:2
        "squareSplit": { "ratio": "1 | 1", "isDraggable": true }, // 方形窗口开拖拽,三档吸附
        "transPages": ["AddressEditPage"],    // 过渡页固定右侧,不被推挤
        "fullScreenPages": ["FullScreenImagePage"], // 进此页退出分栏,返回恢复
        "splitDividerColor": {                // 分割线颜色,深浅色模式分开配
          "light": "#33FFFFFF",
          "dark": "#33000000"
        },
        "enableInSplitScreen": true,          // 窗口分屏下宽高满足条件则保持平行视界
        "enableReducedContainerSize": true    // 虚拟容器:断点/宽度按右侧页面尺寸计算
      }
    }
  },
  "tablet": {
    "displayModeOptions": {
      "wideWindowMode": "original",           // 在 tablet 上单独关掉兼容行为
      "squareWindowMode": "original"
    }
  }
}

第一层是设备类型:common 提供默认配置,phone/tablet 单独配置后覆盖 common。第二层 displayModeOptions 里,wideWindowMode/squareWindowMode 取三个枚举值:navigationSplit(路由由 Navigation 实现)、routerSplit(路由由 Router 实现)、original(关闭兼容行为)。注意 routerSplitOptionsnavigationSplitOptions 不能同时存在,官方明确不建议在启用平行视界的应用里混用两种路由框架。

V哥最想强调的是 homePage:对 Navigation 路由,首页配 "navBar";如果想让某个 NavDestination 当主页,就配它的 name。官方建议主动配置主页——默认的主页识别机制"在有些场景下不能准确识别",识别错了,分栏的左右关系就全乱了。


三、路由模式:mode 0 和 mode 1,两种"左右"哲学

API 26 新增的 mode 字段是这期升级的核心。两种模式对应两种浏览心智(两种模式的交互规则均引自官方能力介绍):

分屏模式与比例预设示意

购物模式(mode: 0)——左右推挤。页面路由跳转时右侧页面始终向左推入,屏幕右侧展示路由栈栈顶页面,左侧展示次栈顶。左侧点商品、右侧出详情;在右侧再点推荐商品,原页面左移、新页面右推。适合"层层深入、随时回退"的浏览流:商品详情、机酒比价、内容连续浏览。临时编辑类页面(如地址编辑)用 transPages 固定在右侧,不被推挤。

导航模式(mode: 1,默认)——固定覆盖。左侧主页保持不变,右侧内容区以覆盖形式切换:左侧点条目,新页面覆盖右侧;右侧点条目,同样覆盖右侧;触发全局返回时,右侧回到上一层级。适合"导航固定、内容切换"的场景:IM 聊天、邮箱、长文阅读、分类导航。

还有个精细控件 pagePairs:配置 {from, to} 跳转关系对,仅在导航模式下生效——从 from 跳 to 时触发分栏,from 在左、to 在右,to 还可以配 "*" 表示任意页面。V哥的理解:mode 是全局的哲学,pagePairs 是对个别入口的精修,两者配合可以做到"全局导航式,个别入口比价式"。


四、比例与分割线:1:2/2:1 预设 + 三档吸附拖拽

这就是标题里"1:2/2:1 随意切"的出处。API 26 在 navigationSplitOptions(或 routerSplitOptions)里新增了 wideSplitsquareSplit 两个对象,内部两个字段:

  • ratio:左右页面比例,格式为 "正整数 | 正整数",范围限制在 1:2 到 2:1 之间,未配置默认 1:1,配超了取范围边界值。V哥的写法习惯:平板这类长方形窗口配 "1 | 2" 让详情占主视野,双折叠的方形展开态配 "1 | 1"
  • isDraggable:开拖拽后 ratio 失效,默认从 1:1 起,三档吸附——在 1:2、1:1、2:1 之间可以拖动。用户自己找到舒服的比例,比开发者猜更聪明。

分割线也有两个开关:splitDividerColor 配深浅色两种颜色(十六进制 #AARRGGBB,官方提醒:应用不适配深色模式时,light 和 dark 配成同色);navigationSplitOptions 独有的 disableDivider 可以干脆隐藏分割线。

配套还有一批"防止左右页打架"的字段,V哥按官方说明列个速查表:

字段作用V哥的用法建议
fullScreenPages进入即退出分栏,返回恢复图片全屏、视频播放页必配
supportLandscapeFullscreen主动请求横屏时退出分栏(默认 true)参数对比大表类页面
dialogSupportSplit弹窗在右半屏显示(默认 true)默认即可,想居中再关
enableReducedContainerSize断点/lpx/窗口宽度按右页尺寸计算强烈建议开,治 UI 截断的头号药方
drawableRectHookWindow.drawableRect 按右页尺寸计算与上一条配套

官方"常见问题"第一条就是 UI 元素被截断——窗口一半宽度装原来的布局,元素当然溢出。除了虚拟容器,官方还给了 on('navDestinationUpdate')onNavDestinationSizeChange() 等监听接口(API 23+)拿页面真实尺寸。V哥的顺序建议:自适应布局优先,虚拟容器兜底,监听接口留给精细场景。


五、应用内分屏:分屏入口 + 一段 ArkTS

7.0 还有一层组合技:应用处于平行视界分栏时,用户点详情页顶部的分屏入口,应用以主窗口形式进入系统窗口分屏,且原窗口继续保持平行视界效果——左边列表加详情,右边再开比价或物流查询,一屏三区(论坛官方解读)。

接入分两步。第一步配置 enableInSplitScreen: true(默认 false,不配就永远不进)。第二步在详情页加按钮,官方给的判断逻辑和拉起方式,V哥按自己的注释习惯整理:

// GoodsDetailPage.ets —— 分屏入口:只在"分栏态 + 未分屏"时露出
import { common, AbilityConstant } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

// 按钮可见性:isEasySplit() 判断是否处于平行视界分栏态,
// windowStatusType 判断是否已处于窗口分屏
Button($r('app.string.enter_split'))
  .visibility(this.getUIContext().isEasySplit() &&
    this.mainWindowInfo.windowStatusType !== window.WindowStatusType.SPLIT_SCREEN
    ? Visibility.Visible : Visibility.None)
  .onClick(() => this.startSplitScreen())

// 拉起应用新实例,指定主窗口占比,以主窗口形式进入系统分屏
private startSplitScreen(): void {
  const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  context.startAbility(
    { bundleName: 'com.vge.demo', abilityName: 'EntryAbility' },
    {
      windowMode: AbilityConstant.WindowMode.WINDOW_MODE_SPLIT_PRIMARY,
      splitRatio: window.SplitRatioPreference.PRIMARY_DOMINANT
    });
}

接口名(isEasySplit()WindowStatusType.SPLIT_SCREENWINDOW_MODE_SPLIT_PRIMARYSplitRatioPreference.PRIMARY_DOMINANT)均出自官方开发指导的示例代码。实际分屏效果以真机实测为准。


六、V哥的判断:什么时候用平行视界,什么时候老老实实写 Navigation

第一期讲一多布局时V哥写过定位:平行视界不替代 Navigation,它是"列表-详情"高频场景的系统级捷径。官方能力介绍里有一张"平行视界与分栏体验对比"表,V哥把结论翻译成大白话:分栏(Navigation 一多)是主动适配,功能完整、控制灵活,适合对布局有精细化定制诉求的应用;平行视界是配置接入,能力相对受限,适合想快速拿到分栏体验的应用。

据此V哥给三条选型判断:

① 页面关系是"路由栈",就用平行视界。 左右页天然是父层级到子层级、用户预期就是"左点右出",电商详情、IM 聊天、邮箱正文——一份 JSON 解决,何必重写。这也是官方列的典型价值场景:购物对比、即时通讯、内容消费、邮件办公。

② 布局要"长成设计稿",就自己写 Navigation。 需要侧边栏、三分栏、跨栏联动、特殊转场、复杂状态同步的,平行视界的固定双页给不了,老老实实用 Navigation 的分栏能力,子页面层级官方建议不超过三层。

③ 两者可以分设备共存。 tablet 层配 original 关掉平行视界、让平板走你自己的 Navigation 分栏;common 留着兼容手机投宽屏、折叠屏这些你顾不上的形态。大屏体验一步到位是理想,配置兜底是现实,先用现实接住用户,再奔理想。


参考与出处

本文涉及的机制、字段与交互规则来自以下官方材料,均为V哥动笔前逐条核验的原文出处:


最后一句:大屏适配的尽头不一定是重构——把路由栈交给系统,把设计稿留给自己,一份 easy_go.json 写对 homePage 和 mode,折叠屏展开的那一秒,你的应用就从"大号手机"变成了"两个页面各得其所"。