组件在扩展到安全区域后渲染异常如何解决
===================

#### 问题现象

当动态计算子组件高度并扩展其安全区域后，父容器布局约束失效，导致子组件渲染异常。

问题截图如下：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/7e/v3/7Lt9XtlCSkqdLKn7zyQ45Q/zh-cn_image_0000002628399648.png?HW-CC-KV=V1&HW-CC-Date=20260709T133923Z&HW-CC-Expire=86400&HW-CC-Sign=3097AEDFCA70FCBE10348930A95527AD0655365AD2DE85320FBAD85F7A4BA58D "点击放大")

代码如下：

import { display } from '@kit.ArkUI';


@Entry
@Component
struct Index {
  build() {
    Column() {
      Column() {
        Text()
          .width('100%')
          .height(this.getUIContext().px2vp(display.getDefaultDisplaySync().width) / (360 / 640))
          .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP\])
          .backgroundColor('#E5E5EA');
      }
      .backgroundColor('#666666');


      Text('上部组件间异常空缺，显示父组件深灰色');
    }
    .width('100%')
    .height('100%');
  }
}

#### 背景知识

*   [expandSafeArea](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-expand-safe-area#expandsafearea)控制组件扩展其安全区域，实现屏幕整体一致，达成沉浸式体验。
*   [height](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-size#height)设置组件自身的高度，缺省时使用元素自身内容需要的高度。若子组件的高度大于父组件的高度，则会超出父组件的范围。入参为[Length](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-types#length)，支持确切数值和百分比形式。
*   [display.getDefaultDisplaySync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-display#displaygetdefaultdisplaysync9)：获取当前默认的[display](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-display#display)对象。

#### 问题定位

根据组件高度变化可知，组件使用expandSafeArea后仍保持设置的固定高度大小。原因是expandSafeArea会先扩展组件到指定安全区域。此时因为组件固定高度，组件就会表现为原大小上移至安全区域。但是，expandSafeArea是仅影响组件本身的属性（减少组件对组件树的影响，降低重绘压力），对于父组件而言组件的占用位置不变，所以父组件会有一部分空间剩余出来。

#### 分析结论

组件使用expandSafeArea后不建议固定高度。可以使用百分比高度组件，在扩展到安全区域后，调整高度阶段会保持非安全区域占用父组件非安全区域的百分比。

#### 修改建议

aboutToAppear提前计算百分比，组件使用百分比作为高度属性入参。

代码如下：

import { display } from '@kit.ArkUI';


@Entry
@Component
struct ExpansionException {
  @State heightNum: number = 0;


  aboutToAppear(): void {
 _   // 根据高宽比计算高度_
    this.heightNum = display.getDefaultDisplaySync().width / (360 / 640) / display.getDefaultDisplaySync().height \* 100;
  }


  build() {
    Column() {
      Column() {
        Text()
          .width('100%')
          .height(this.heightNum.toString() + '%')
          .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP\])
          .backgroundColor('#E5E5EA');
      }
      .backgroundColor('#666666');


      Text('上部组件间异常空缺，显示父组件深灰色');
    }
    .width('100%')
    .height('100%');
  }
}

#### 常见FAQ

Q：设置了expandSafeArea属性不生效？

A：使用expandSafeArea属性常会触发以下限制，导致组件并没有扩展安全区域。

*   设置expandSafeArea属性进行组件绘制扩展时，组件不能设置固定宽高尺寸。可尝试用百分比或padding改变组件宽高。
*   设置expandSafeArea属性的组件需与安全区域边界重合。
*   当设置expandSafeArea属性的组件的父组件是滚动类容器，需设置父组件的clip属性，不裁剪内部组件。参考[顶部或底部背景延伸案例](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-multi-device-window-immersive#section166836535168)。

Q：左右两个Column分别设置高度为'calc(100%)'和'100%'。其中设置了'calc(100%)'的Column通过expandSafeArea扩展至状态栏后维持了原有的高度，仅仅只是实现了向上平移的效果，设置了'100%'的Column通过expandSafeArea扩展至状态栏后则是在原有高度的基础上向上延伸。这是为什么？

A：设置expandSafeArea属性进行组件绘制扩展时，建议组件尺寸不要设置固定宽高（百分比除外），当设置固定宽高（包括设置"auto"）时，扩展安全区域的方向只支持\[SafeAreaEdge.TOP, SafeAreaEdge.START\]，扩展后的组件尺寸保持不变。而calc计算得到的高度会被视作一个固定值，因此扩展后保持原有尺寸不变。