HarmonyOS 7 两个 ContainerReader 并排,右侧为什么宽度为 0?layoutWeight 才是关键

在 API 26 的横向 Flex 中放两个 ContainerReader,本想让左右内容各占一半,结果第一个铺满整行,第二个几乎看不见。这个现象容易被误判成容器断点没有更新。实际先要查的是父容器如何分配剩余宽度:官方文档明确说明,多个 ContainerReader 作为同级子组件时,默认按书写顺序由第一个占满剩余空间,其余组件的主轴大小可能是 0。

本文只讨论两个同级容器争用剩余空间的情况。下面用同一组布局分别复现和修复,方便直接对照。

案例一:两个容器都没有权重,后一个消失

在 DevEco Studio 26.0.0 的 API 26 工程中新建页面,把下面代码放进去。这里给父容器明确宽高,排除父级尺寸不确定的干扰。

import { ContainerReader, Size } from '@kit.ArkUI';

@Entry
@Component
struct TwoReadersWithoutWeight {
  @State leftSize: Size = { width: 0, height: 0 };
  @State rightSize: Size = { width: 0, height: 0 };
  @State leftBp: WidthBreakpoint = WidthBreakpoint.WIDTH_MD;
  @State rightBp: WidthBreakpoint = WidthBreakpoint.WIDTH_MD;

  build() {
    Flex({ direction: FlexDirection.Row }) {
      ContainerReader({ size: this.leftSize!!, widthBreakpoint: this.leftBp!! }) {
        Text(`左侧 ${this.leftSize.width}vp`).width('100%')
      }
      .backgroundColor('#DBF5EA')

      ContainerReader({ size: this.rightSize!!, widthBreakpoint: this.rightBp!! }) {
        Text(`右侧 ${this.rightSize.width}vp`).width('100%')
      }
      .backgroundColor('#FFE1D9')
    }
    .width('100%')
    .height(240)
  }
}

观察点不是“屏幕宽度够不够”,而是 rightSize.width 和红色区域是否有可见宽度。按照官方描述,第一个 Reader 先拿走剩余空间,第二个主轴宽度为 0。不要试图修改 rightSize 来给它分配宽度;size 是读取布局结果的双向绑定状态,不是设置容器尺寸的入口。

案例二:固定侧栏之外,两块内容平分

改成左侧固定 100vp,两个 Reader 都设 layoutWeight(1)。关键是两个都设置,而且用两个独立的尺寸状态,不能让两个 Reader 共享同一个 Size 对象。

import { ContainerReader, Size } from '@kit.ArkUI';

@Entry
@Component
struct TwoReadersWithWeight {
  @State firstSize: Size = { width: 0, height: 0 };
  @State secondSize: Size = { width: 0, height: 0 };
  @State firstBp: WidthBreakpoint = WidthBreakpoint.WIDTH_MD;
  @State secondBp: WidthBreakpoint = WidthBreakpoint.WIDTH_MD;

  build() {
    Flex({ direction: FlexDirection.Row }) {
      Column() { Text('导航') }
        .width(100)
        .height('100%')
        .backgroundColor('#E8E9E7')

      ContainerReader({ size: this.firstSize!!, widthBreakpoint: this.firstBp!! }) {
        Text(`主列表 ${this.firstSize.width}vp`)
      }
      .layoutWeight(1)
      .backgroundColor('#DDF3E8')

      ContainerReader({ size: this.secondSize!!, widthBreakpoint: this.secondBp!! }) {
        Text(`详情 ${this.secondSize.width}vp`)
      }
      .layoutWeight(1)
      .backgroundColor('#D6E9FF')
    }
    .width('100%')
    .height(240)
  }
}

固定侧栏和两个 ContainerReader 的宽度分配示意

示意图以 900vp 的父容器为例:侧栏先占 100vp;剩下 800vp 按 1:1 分给两个 Reader,各 400vp。实际数值还会受父容器内边距、间距和设备窗口宽度影响,不应把 400vp 写进业务断言。我们真正要验证的是:两个值都大于 0,且在同权重、无额外宽度约束时接近相等。

为什么用权重,而不是给每块写死 400vp

做法窄窗口或分屏时容器断点能否反映真实局部尺寸
两块固定宽度容易溢出或被压缩能反映结果,但布局本身不弹性
只给第二块设权重第一块仍可能抢走空间容易继续出现一侧为 0
两块都设 layoutWeight(1)跟随剩余空间均分两块分别回写自己的尺寸与断点

这也解释了 ContainerReader 与窗口断点的区别:同一个窗口里,侧栏、主列表、详情的局部可用宽度可以完全不同。主列表的列数应按它自己的容器尺寸决定,而不是拿窗口总宽度推断。

排查顺序与验证边界

  1. 先确认父 Flex 有明确宽高;官方要求容器尺寸不要反过来依赖子节点决定。
  2. 确认 size、widthBreakpoint 使用各自的 @State,并以 !! 双向绑定;不加 !! 会失去回写。
  3. 检查同级固定宽度组件先占走多少空间,再看 Reader 是否都设置了权重。
  4. 在 API 26 真机或模拟器中切换全屏、窄窗口、分屏,观察两块实际宽度是否均为正,并检查断点随各自容器变化。

本文的布局规则、接口与边界已按华为 2026-09-09 更新的官方指南核对;文中的 900/100/400vp 是解释性算例。当前没有将上述 ArkTS 工程在 API 26 SDK 和真机上编译运行,因此不把示意计算写成设备实测结论。复现时请以两组页面的可见结果和 Size 回写值为准。

官方依据:容器断点 ContainerReader 开发指南。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐