背景案例:当我们应用中有一个输入功能,输入个数需要用户动态修改,这时原有的固定布局就不能满足这个需求了,因此就要用到动态添加布局。
简单演示:
实现原理:
自定义声明式节点 (BuilderNode)提供能够挂载系统组件的能力,支持采用无状态的 UI 方式,通过全局自定义构建函数 @Builder 定制组件树。
一个新建的 BuildNode 在 build 之后才能通过 getFrameNode 获取到一个指向根节点的 FrameNode 对象,否则返回 null
实现过程:
1.定义一个全局的 Build 修饰的布局用于动态添加到容器中
2.定义一个参数对象,可以传入参数或者接收回调
3.添加节点到布局中
注意:
1.@Builder 嵌套使用的时候需要保证内外的 @Builder 方法的入参对象一致。最外层的 @Builder 只支持一个入参。需要操作 BuilderNode 中的对象时,需要保证其引用不被回收。
2.若前端对象 BuilderNode 无法释放,容易导致内存泄漏。建议在不再需要对该 BuilderNode 对象进行操作时,开发者应主动调用 dispose 释放后端节点,以减少引用关系的复杂性,降低内存泄漏的风险。
实现源码:
import { BuilderNode, NodeContent } from '@kit.ArkUI';
import { ArrayList } from '@kit.ArkTS';
class User {
name: string = ''
phone: string = ''
}
interface ParamsInterface {
user: User
save: (user: User) => void;
delete: (user: User) => void
}
@Builder
function buildChildViw(params: ParamsInterface) {
Column({ space: 5 }) {
TextInput({ placeholder: '输入姓名' }).onChange((e) => {
params.user.name = e
})
TextInput({ placeholder: '输入手机号' }).onChange((e) => {
params.user.phone = e
})
Row(){
Button('确定').onClick(() => {
params.save(params.user)
})
Button('删除').onClick(() => {
params.delete(params.user)
})
}
}
}
@Entry
@ComponentV2
struct AddNodeTest {
content: NodeContent = new NodeContent();
@Local paramMap: ArrayList<user> = new ArrayList();
@Local inputInfo: string = ''
getInputUserInfo() {
this.inputInfo=''
this.paramMap.forEach((value: User, index?: number) => {
this.inputInfo += index + ' name:' + value.name + ' phone:' + value.phone + '\n'
});
}
build() {
Column({ space: 10 }) {
ContentSlot(this.content)
Button('添加联系人')
.onClick(() => {
let buildNode = new BuilderNode<[ParamsInterface]>(this.getUIContext());
buildNode.build(wrapBuilder<[ParamsInterface]>(buildChildViw), {
user: new User(), save: (user: User) => {
this.paramMap.add(user)
}, delete: (user: User) => {
this.paramMap.remove(user)
this.content.removeFrameNode(buildNode.getFrameNode())
}
}, { nestingBuilderSupported: true });
this.content.addFrameNode(buildNode.getFrameNode());
})
Button('显示联系人').onClick(() => {
this.getInputUserInfo()
})
Text(this.inputInfo)
}
.width('100%')
.height('100%')
}
}
</user>
复制代码
代码有不严谨的地方,只是演示一下动态添加布局的方法,实际开发中还得根据需求进行修改完善。
评论