鸿蒙开发:动态添加节点

前言

本文基于Api13

做过Android的同学都知道,我们可以拿到任意一个容器组件,比如LinearLayout或者RelativeLayout,或者其他容器视图,我们都可以进行自由的添加子组件,方便我们去处理一些子元素动态变化的场景,然而由于鸿蒙的ArkUI是声明式的UI,我们无法拿到一个容器组件进行对其动态的添加。

比如一个Column组件,我们如何动态的添加子组件呢?可能很多人都会想到,通过条件判断的形式进行追加。

声明组件类型,这里,可以创建一个组件对象,把组件的相关属性,数据声明一下,这里,我简单的只设置了一个类型。

TypeScript 复制代码
enum NodeType {
  Text, Image
}

通过不断的改变以上的组件类型,我们在Column组件中进行遍历,根据类型判断使用哪个组件。

TypeScript 复制代码
Column() {
      ForEach(this.mNodeType, (type: NodeType) => {
        if (type == NodeType.Text) {
          Text("我是一个Text组件")
        } else if (type == NodeType.Image) {
          Image($r("app.media.app_icon"))
            .width(20)
            .height(20)
        }
      })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)

显然以上的方式是不够友好,因为组件都是固定的,不能动态的想添加哪个就添加哪个,而且相关属性配置起来也是十分的复杂,即便能够千方百计的实现出来,也远远不如Android端那样灵活。

那么,有没有一种方式可以脱离UI的限制,实现灵活多变的想追加哪个组件就追加哪个组件呢?这就是本篇文章所阐述的内容,通过NodeController和FrameNode来实现。

NodeController

NodeController主要用于实现自定义节点的创建、显示、更新等操作的管理,并负责将自定义节点挂载到NodeContainer上,NodeController是一个抽象类,使用的时候,我们可以单独创建一个子类用于继承它。

简单一个Demo,使用NodeContainer进行展示一个文本组件。

TypeScript 复制代码
@Entry
@Component
struct DemoPage {
  private myNodeController: MyNodeController = new MyNodeController()

  build() {
    Column() {
      NodeContainer(this.myNodeController)
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

@Builder
function TextBuilder(message: string) {
  Text(message)
}

class MyNodeController extends NodeController {
  private buttonNode: BuilderNode<[string]> | null = null
  private wrapBuilder: WrappedBuilder<[string]> = wrapBuilder(TextBuilder)

  makeNode(uiContext: UIContext): FrameNode {
    if (this.buttonNode == null) {
      this.buttonNode = new BuilderNode(uiContext)
      this.buttonNode.build(this.wrapBuilder, "简单一个文本")
    }
    return this.buttonNode!.getFrameNode()!
  }
}

FrameNode

FrameNode表示组件树的实体节点,通过FrameNode我们可以实现添加,删除,获取子节点,主要方法有:

方法 参数 概述
appendChild FrameNode 在FrameNode最后一个子节点后添加新的子节点。当前FrameNode如果不可修改,抛出异常信息
removeChild FrameNode 从FrameNode中删除指定的子节点。当前FrameNode如果不可修改,抛出异常信息。
clearChildren 无参 清除当前FrameNode的所有子节点。当前FrameNode如果不可修改,抛出异常信息。
getChild number 获取当前节点指定位置的子节点。
insertChildAfter FrameNode, FrameNode/null 在FrameNode指定子节点之后添加新的子节点。当前FrameNode如果不可修改,抛出异常信息。
getChildrenCount 无参 获取当前FrameNode的子节点数量。

在添加组件时,主要通过typeNode来创建组件,目前支持二十多种组件形式,比如常见的容器组件,文本,图片,列表等等,基本涵盖了日常中常见的。

比如,我们创建一个Column组件,在Column组件中再追加一个Text文本组件。

TypeScript 复制代码
@Entry
@Component
struct DemoPage {
  private myNodeController: MyNodeController = new MyNodeController()

  build() {
    Column() {
      NodeContainer(this.myNodeController)
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


class MyNodeController extends NodeController {
  makeNode(uiContext: UIContext): FrameNode {
    let rootNode = new FrameNode(uiContext)
    //创建一个Column组件
    let column = typeNode.createNode(uiContext, "Column")
    column.initialize()
      .width("100%")
      .height("100%")
      .justifyContent(FlexAlign.Center)
    rootNode.appendChild(column)
    //创建一个Text组件
    let text = typeNode.createNode(uiContext, "Text")
    text.initialize("文本组件")
      .fontColor(Color.Red)
      .fontSize(20)
      .padding(10)
      .border({ width: 1, color: Color.Red })
    column.appendChild(text)
    return rootNode
  }
}

我们运行一下,看下效果。

相关总结

流程就是,通过typeNode来创建自己的组件,然后使用追加到FrameNode节点中,然后将自定义节点挂载到NodeContainer上即可,主要使用场景,需要动态创建组件的场景。

相关推荐
xiaolizi5674897 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100017 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜7 小时前
Python入门篇【文件处理】
android·java·python
我不是8神7 小时前
gin与gorm框架知识点总结
ios·iphone·gin
遥不可及zzz10 小时前
Android 接入UMP
android
奋斗的小青年!!11 小时前
Flutter浮动按钮在OpenHarmony平台的实践经验
flutter·harmonyos·鸿蒙
Georgewu11 小时前
【HarmonyOS应用开发】鸿蒙应用实现横竖屏切换的两种方式以及注意事项
harmonyos
Coder_Boy_12 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab13 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言
冬奇Lab13 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug