鸿蒙开发:动态添加节点

程序员一鸣
• 阅读 21

前言

本文基于Api13

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

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

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

enum NodeType {
  Text, Image
}

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

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进行展示一个文本组件。

@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文本组件。

@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上即可,主要使用场景,需要动态创建组件的场景。

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
CocosCreator 搭建场景和坐标系转换(第二篇)
前言:我们在玩随便一个游戏时,都会发现游戏有很多个的界面,比如(登录界面、主菜单界面,游戏界面、商店界面等),其实这都是一个个的场景,我们通过代码来控制不同场景之间的切换。一个场景里面会有很多的节点组成,为制作出多种多样的节点,我们是通过在节点上挂载不同的组件来实现。在搭建场景时,需要用到一个重要概念坐标,这个坐标包括
Wesley13 Wesley13
3年前
GoJS API学习
varnode{};node"key""节点Key";node"loc""00";//节点坐标node"text""节点名称";//添加节点通过按钮点击,添加新的节点到画布myDiagram.model.addNodeData(nod
Easter79 Easter79
3年前
TypeScript Generics(泛型)
软件工程的一个主要部分就是构建组件,构建的组件不仅需要具有明确的定义和统一的接口,同时也需要组件可复用。支持现有的数据类型和将来添加的数据类型的组件为大型软件系统的开发过程提供很好的灵活性。在C和Java中,可以使用"泛型"来创建可复用的组件,并且组件可支持多种数据类型。这样便可以让用户根据自己的数据类型来使用组件。泛型的简单案例首先,
Wesley13 Wesley13
3年前
JQ动态生成节点绑定事件无效问题
最近做项目的时候遇见了一个问题,通过jq将动态节点绑定到dom节点上,并且为动态节点绑定方法,此方法再次为动态节点添加动态节点,但在刷新之后,动态节点上的方法失效了,过程为:创建动态节点动态节点绑定方法添加动态节点刷新后点击动态节点方法失效。<!DOCTYPEhtml<html<head</head<body
Stella981 Stella981
3年前
Angular使用总结
  之前自己写的公共组件,都是会先引入,需要调起的时候再通过service控制公共组件状态、值、回调函数什么的。但是有一些场景不适合这种方式,还是动态添加组件更加好。通过写过的一个小组件来总结下。创建组件  场景:鼠标移动到图标上时,展示解释性的说明文字。那就需要创建一个普通的tooltip组件。如下:!(https://oscim
Stella981 Stella981
3年前
CocosCreator 代码组件(创建销毁节点、访问节点和组件) (第四篇)
前言:在游戏开发中,我么都是通过代码来控制场景中的节点,下面讲解怎么用代码,创建节点、销毁节点、访问节点、访问组件。一、创建和销毁节点1\.创建新节点除了通过场景编辑器创建节点外,我们也可以在脚本中动态创建节点。通过newcc.Node()并将它加
Stella981 Stella981
3年前
CocosCreator 代码组件(创建与使用、cc.Class类型、生命周期函数)(第三篇)
前言:在前面一篇中讲解了场景的搭建,现在开始介绍一个重要的部分代码组件,通过在不同节点上挂载不同逻辑功能的代码组件来实现游戏的开发。VSCode下载链接:https://code.visualstudio.com/(https://www.oschina.net/action/GoToLink?urlhttps%3A%
使用 Taro 开发鸿蒙原生应用 —— 快速上手,鸿蒙应用开发指南
随着鸿蒙系统的不断完善,许多应用厂商都希望将自己的应用移植到鸿蒙平台上。最近,Taro发布了v4.0.0beta.x版本,支持使用Taro快速开发鸿蒙原生应用,也可将现有的小程序转换为鸿蒙原生应用。在《使用Taro开发鸿蒙原生应用》系列文章中,我们已经介绍
京东云开发者 京东云开发者
7个月前
鸿蒙跨端实践-ArkTS和CAPI的混合开发实现
一、背景在文章中,讲述了动态化适配鸿蒙的方案实现,当在鸿蒙系统进行UI渲染的时候,我们使用了系统的组件进行递归渲染。在iOS和Android也是借助各自系统组件进行的渲染,但是在鸿蒙系统会存在以下4个严重问题:1.UI层级过多以金融APP理财频道页中的一个
京东云开发者 京东云开发者
2个月前
使用 Taro 开发鸿蒙原生应用 —— 快速上手,鸿蒙应用开发指南
作者:京东零售利齐诺随着鸿蒙系统的不断完善,许多应用厂商都希望将自己的应用移植到鸿蒙平台上。最近,Taro发布了v4.0.0beta.x版本,支持使用Taro快速开发鸿蒙原生应用,也可将现有的小程序转换为鸿蒙原生应用。在《使用Taro开发鸿蒙原生应用》系列