鸿蒙实现动态增删 View,看这一篇就够了!!

1,883 阅读4分钟

在 Android 开发的过程中,我们经常使用 addViewremoveView等实现在 java 代码中动态添加和删除 View 的能力

但是在鸿蒙中,组件是相对于静态的结构,而且鸿蒙也没有提供类似于 addViewremoveView的方法,那我们怎么来实现动态化增删组件的能力呢

1. 使用 ForEach 实现动态化增删组件

1.1. ForEach 的入参

翻阅了鸿蒙的官方文档,终于看到了一种方法来解决这个问题,那就是使用 ForEach这个组件

这个组件的官方定义如下

ForEach(
  arr: Array,
  itemGenerator: (item: any, index: number) => void,
  keyGenerator?: (item: any, index: number) => string
)
  • arr

    arr 有多少个元素,ForEach 就会渲染多少个组件

  • itemGenerator

    将 arr 中的元素转换为对应的组件样式

    决定了组件长什么样子

  • keyGenerator

    生成唯一的 key

1.2. ForEach 的渲染

在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

ForEach 的渲染分为两种:

  • 首次渲染

在ForEach首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。

  • 非首次渲染:

在ForEach组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件。

2. ForEach 的简单 demo

@Entry
@Component
export struct MyPage {
  @State items: Item[] = [
    { text: "1" },
    { text: "2" },
    { text: "3" },
  ]

  build() {
    Column() {
      ForEach(
        this.items,
        (item: Item, index: number) => {
          Text(item.text)
            .width(40)
            .height(40)
        }
      )

      Button("add item ")
        .onClick(
          ()=>{
            this.items.push(
              { text: "11" },
            )
          }
        )
    }
    .height('100%')
    .width('100%')
  }
}


interface Item {
  text: string,
}

运行后的状态为这样:每次点击按钮,都会新增一个

3. ForEach 的注意事项

3.1. 数组中元素子属性发生变化时的处理

数组中元素子属性发生变化时,鸿蒙默认是不会触发渲染的

解决办法是:使用@Observed@ObjectLink

3.2. 最好自定义 key,key 中不含index

鸿蒙的默认 key

鸿蒙 Foreach 的默认key 为

(item: T, index: number) => {
  //👇 这里带着 index
  return index + '__' + JSON.stringify(item); 
}

默认的 key 里面带着 index,如果我们在对数组进行操作的过程中,将元素的 index改变了,就会导致 index 改变的元素对应的组件被重绘

鸿蒙 ForEach 的渲染

鸿蒙通过 key 来判断组件是新组件还是现有组件

index 改变,key 就改变了,鸿蒙就会执行两个操作

  1. 删除原来的 key 对应的组件
  2. 重新创建组件

就会导致原来的组件中的所有状态全部没有了比如说我们正在执行动画,但是 key 被改变了,动画就会中断,重新创建的组件没有动画执行的状态,如果我们想继续执行动画,那么必须保存动画的状态,这样成本太大了,

而我们只需要自定义 key,让 index 不在 key 里面,就解决这个问题了

为什么 index 会改变?

比如说中间的元素被删除了,后面的元素 index 就会改变

而且我们不可能在执行时,一定保证移除的是最后一个元素,添加的一定在最后面

而如果我们自定义key 里面没有 index,那么我们可以随意的增删数组中的元素

自定义 key 的优点

  • 可以让我们任意对数组进行操作,
  • 优化性能

比如说我们只是删除了数组中间的一个元素,后面的元素没有任何的改变

如果我们使用鸿蒙默认的 key,后面的元素 index 改变,key 改变,全部会重绘

如果我们自定义 key,后面的元素就不会重绘了,节省性能

自定义 key 的注意事项

  1. 一定不要包含 index
  2. key 的组成部分尽量全部为常量,不要变量

如果是变量,保证组件生命周期内不会变化

或者如果生命周期发生变化,是自己预期内的

“本文正在参加华为鸿蒙有奖征文征文活动”