03 把 InsightBoard 的悬停态处理完以后,我把同一套工程放到平板和 PC / 2in1 上重新看了一遍。

这次最明显的问题不是组件错位,而是页面太像手机了。

窗口已经 1180vp 宽,左侧还保留手机风格的底部导航,中间列表只占一小块,详情区域留出大面积空白。功能都能用,但大屏真正增加的空间并没有换来更高的信息效率。

所以 04 不再增加新的 Fold API,而是处理大屏下的三件事:

导航层级
列表密度
自由窗口缩放

本轮固定数据:

taskId: adapt_20261002_04
device: PC / 2in1
window: 1440 × 960 px
viewport: 1180 × 786 vp

mode: EXPANDED
navigation: RAIL
density: DENSE

railWidth: 72vp
listWidth: 320vp
detailMinWidth: 480vp
gutter: 24vp

visibleItems: 9
selectedItem: insight_042
filter: 全部

resize:
960vp → 1180vp

status: READY

一、大屏不是把 COMPACT 页面撑开

InsightBoard 的第一版 EXPANDED 很简单:MEDIUM 双栏再加一个 NavigationRail。

结构没错,问题出在信息密度。

列表卡片仍然使用手机上的大图、标题两行、摘要两行和很大的上下间距。1180vp 宽时一屏只能看到 5 条。

右侧详情也保留手机大 Padding,结果就是“看起来很宽,但能看到的信息没多多少”。

我重新定义大屏目标:

导航常驻
列表更紧凑
详情更宽
辅助信息直接展示
减少无意义页面跳转

HarmonyOS 的多设备适配指南本身也强调,要根据屏幕尺寸和使用场景重新规划信息层级、导航结构和关键操作区域,而不是简单放大。对 InsightBoard 来说,大屏的价值应该是“少跳一层、同屏多看一些”,而不是“同一张卡片变得更宽”。

二、Navigation 模式要随空间变化,但页面栈不能重建

大屏里 InsightBoard 使用 Rail。

当前结构:

Navigation Rail
→ Insight List
→ Detail

自由窗口缩窄到 MEDIUM 后:

List
→ Detail

继续缩到 COMPACT:

Stack

这意味着同一个 insight_042 可能经历“三栏 → 双栏 → 单页栈”。

如果每次都新建一个 NavigationController,业务状态一定会跳。

04 新增 AdaptiveNavigationRouter.ets:

export enum NavigationLayout {
  STACK = 'STACK',
  SPLIT = 'SPLIT',
  RAIL = 'RAIL'
}

export class AdaptiveNavigationRouter {
  resolve(
    mode: LayoutMode
  ): NavigationLayout {
    if (mode === LayoutMode.COMPACT) {
      return NavigationLayout.STACK
    }

    if (mode === LayoutMode.MEDIUM) {
      return NavigationLayout.SPLIT
    }

    return NavigationLayout.RAIL
  }
}

Router 只返回结构模式。

selectedItemId / filter / scrollOffset / detailTab 都继续保存在 Store。

这一点和 01、02 的连续性设计是同一条主线:布局可以重排,业务上下文不能被布局重排顺手重置。

三、EXPANDED 里新增的是信息,而不是装饰

这次我给三栏定了明确职责。

1. Rail:72vp

只放一级入口:

首页
洞察
分析
收藏
设置

不放当前文章标题,不放业务筛选。

2. List:320vp

列表改成紧凑卡片:

小缩略图
一行标题
时间
一枚状态

本轮同屏可见从 5 条提高到 9 条。

3. Detail:最小 480vp

详情区域把原来需要点第二层页面才能看到的信息直接展开:

标签
进度
来源
更新时间
相关指标

这个变化才是大屏的价值。

不是“同一张手机卡片变宽”,而是少一次跳转。

四、信息密度本身也应该是一个策略

之前页面里直接写:

.padding(24)
.fontSize(18)

PC 版改成:

.padding(16)
.fontSize(16)

几轮以后组件里全是设备判断。

最后我增加 DensityPreset:

export enum DensityPreset {
  COMPACT = 'COMPACT',
  COMFORTABLE = 'COMFORTABLE',
  DENSE = 'DENSE'
}

export interface DensityTokens {
  pagePadding: number
  cardGap: number
  listItemHeight: number
  titleSize: number
}

export function resolveDensity(
  mode: LayoutMode
): DensityTokens {
  if (mode === LayoutMode.EXPANDED) {
    return {
      pagePadding: 20,
      cardGap: 10,
      listItemHeight: 72,
      titleSize: 16
    }
  }

  if (mode === LayoutMode.MEDIUM) {
    return {
      pagePadding: 20,
      cardGap: 14,
      listItemHeight: 84,
      titleSize: 17
    }
  }

  return {
    pagePadding: 16,
    cardGap: 16,
    listItemHeight: 96,
    titleSize: 18
  }
}

这段代码解决的是“适配参数散落在几十个组件里”的问题。

后面如果 PC 想再提高密度,只改策略,不需要满项目搜索 padding(16)。

五、自由窗口场景里,设备是 PC,但页面可能重新变成 MEDIUM

这一篇特意没有写:

PC = EXPANDED

因为自由窗口是最能暴露这个错误的场景。

PC 上把窗口从 1180vp 缩到 780vp:

device 还是 PC
mode 已经变成 MEDIUM

此时 Rail 应该收起。

HarmonyOS 多窗口布局适配文档明确指出,进入悬浮窗或分屏后,窗口尺寸和宽高比会变化,应用应根据窗口尺寸更新布局,并可通过 windowSizeChange 监听变化。

所以 04 没有增加新的“PC 判断”,还是继续使用最开始的 BreakpointPolicy。

这种连续性比多写一个设备枚举更重要。

六、我给自由窗口加了最小宽度,但不把它当断点替代品

PC 自由窗口缩得太小时,三栏已经没有意义。

当前 InsightBoard 的工程下限:

完整三栏:
建议 >= 960vp

MEDIUM 双栏:
600~839vp

COMPACT:
<600vp

注意这里的 840~959vp。

虽然 BreakpointPolicy 已经进入 EXPANDED,但大屏三栏还不一定展开到完整 Rail。

我最终增加一个 LargeScreenShell 内部策略:

private resolveRailVisible(
  widthVp: number
): boolean {
  return widthVp >= 960
}

也就是说:

840~959vp
= EXPANDED content density
+ no permanent rail

>=960vp
= full three-pane large shell

这样断点仍然代表整体布局级别,Shell 内部还可以做更细的组件显隐。

不会为了一个 Rail 再新增第四档 Breakpoint。

七、窗口变宽时,不应该把列表拉成无限宽

这次还有一个很明显的视觉问题。

窗口从 960vp 拉到 1180vp 后,如果列表按 30% 比例增长,列表会越来越宽,详情反而没有得到足够空间。

所以 04 改成固定 / 约束组合:

rail = 72vp
list = 320vp
gutter = 24vp
detail = remaining
detail min = 480vp

大屏继续变宽时,主要增长详情区域。

列表里的标题长度本来就有限,没有必要跟着窗口无限扩张。

这种“固定局部 + 弹性主内容”的方式,比三个区域都按百分比更适合 InsightBoard。

八、同一条 selectedItem 必须在三种导航结构里有同一语义

这次我又遇到一个比布局更细的问题。

COMPACT 里 selectedItemId 表示当前 pushed 详情页;MEDIUM 里它表示右侧详情;EXPANDED 里它又表示列表选中项和详情源。

如果三个组件各自维护状态,看起来都是 insight_042,实际来源却不同。

最后我把“选中洞察”收口成 Store 的唯一值:

export class InsightSelectionStore {
  private selectedItemId: string =
    'insight_042'

  get(): string {
    return this.selectedItemId
  }

  select(id: string): void {
    this.selectedItemId = id
  }
}

Navigation 只负责“怎么显示”,不再拥有选中值。

这样自由窗口在 1180vp → 780vp → 520vp 来回缩放时,结构变三次,选中项始终不变。

九、筛选条件也不能因为列表组件换了就丢

04 里固定筛选:

filter = 全部

这看起来不起眼,但它是另一个状态连续性检查点。

DENSE 列表和 COMFORTABLE 列表不是同一个组件。如果 filter 被写在 ListPane 自己的 @State 里,结构替换时就会回默认。

现在筛选、排序和 selectedItem 都在业务 Store。

布局只消费:

filter
sort
selectedItem

这一点后面 05 做多窗口恢复时会继续用到。

十、DevEco 图里最重要的是 960 → 1180,而不是设备名

最终开发图:

HiLog:

taskId=adapt_20261002_04

windowSizeChange
960vp → 1180vp

mode=EXPANDED
navigation=RAIL

density=DENSE
visibleItems=9

selectedItem preserved
insight_042

filter preserved
全部

status=READY

这里我没有写“device=PC,所以 mode=EXPANDED”。

相反,日志始终保留 viewport。

只要窗口缩回 780vp,即使设备字段还是 PC,Navigation 也会回到 SPLIT。

十一、大屏适配还要检查键鼠和窗口状态,但这一篇先不扩题

PC / 2in1 真正产品化还会继续遇到:

键盘焦点
鼠标 Hover
右键
拖拽
快捷键
子窗口
独立子窗
窗口层级

HarmonyOS 7 API 26 的子窗口能力里也出现了自由窗口下独立子窗相关能力。

但这些没有塞进 04。

这一篇的目标仍然是“同一个主窗口如何根据空间重排导航和信息密度”。

如果把键鼠、子窗全部混进来,文章会失去主线。

后面 05 会处理多窗口和页面栈恢复,届时再把窗口生命周期放进来更合适。

十二、运行结果:更大的窗口,终于带来了更高的信息效率

最终运行图:

统一数据:

taskId: adapt_20261002_04
device: PC / 2in1
window: 1440 × 960 px
viewport: 1180 × 786 vp
mode: EXPANDED
navigation: RAIL
density: DENSE
railWidth: 72vp
listWidth: 320vp
detailMin: 480vp
visibleItems: 9
selectedItem: insight_042
filter: 全部
status: READY

这一步完成以后,InsightBoard 已经覆盖了四种明显不同的布局阶段:

COMPACT 手机
MEDIUM 折叠屏展开
HOVER 半折叠
EXPANDED 平板 / PC

更重要的是,它们并不是四套工程。

仍然是同一个 Store、同一条 selectedItem、同一个 BreakpointPolicy,以及按场景拆出来的 Layout Coordinator。

下一轮会继续 05、06。

05 会处理真正的多窗口生命周期:主窗口缩放、页面栈、详情页、窗口退出再回来时业务任务怎么保持。

06 最后做全系列回归:手机、折叠屏、悬停、平板、PC / 2in1 一起跑,检查布局抖动、重复监听、状态丢失和资源释放。

做到 06 后,这个系列会按原计划正式结束,不继续无限追加。

参考资料

  • HarmonyOS 多设备通用适配指南:https://developer.huawei.com/consumer/cn/multidevice/adaptive-apps/
  • 多窗口布局适配:https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V14/multi-window-layout-adapt-V14
  • 子窗口开发指导:https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/subwindow-guide
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐