动态组件使用指导
不可见组件:在程序运行时创建组件——按钮、标签、布局……任何组件都可以,拓展组件也可以; 还能设置属性、调用方法、删除、调整顺序、移到别的布局,或用 JSON 模板一次创建一批。 适合组件个数由数据决定的界面:问卷的题目、购物车的商品、聊天气泡等。
本组件内化自第三方拓展 DynamicComponents(作者 Yusuf Cihan,MIT 许可证),积木与原拓展一致。
先看是不是用布局列表框更合适:只是「一行一条数据」的列表或网格,用布局列表框更省事, 数据绑定、点击事件都是现成的,而且滚动时组件会复用,数据再多也不卡。
要点
- 每个动态组件创建时给一个编号(文本,不能重复),之后用编号取回、删除它;不关心编号时用生成编号(
GenerateID)。 - 组件只能创建在布局(或画布)里,不能直接创建在屏幕上,所以先在设计器里放一个空的布局当容器。
- 组件类型写英文类型名,如
Button、Label、HorizontalArrangement;也可以传一个现有组件(创建同类型的新组件,拓展组件用这种办法)。 - 动态组件的事件用「任意组件」积木接:在代码块编辑器左侧「任意组件」里拖出如「任意按钮.被点击」,
事件参数
component就是被点的那个按钮,再用取编号(组件)(GetId)知道是哪一个。
快速上手:按数据生成一排按钮
设计器里放一个垂直布局 垂直布局_容器:
各案例独立使用;组合到同一屏幕时,将同名事件的处理合并到一个事件积木中。
global fruits = ["苹果", "香蕉", "橙子"]
when Screen1.Initialize() {
foreach name in fruits {
动态组件1.Create(垂直布局_容器, "Button", name)
动态组件1.SetProperty(动态组件1.GetComponent(name), "Text", join("买", name))
}
}
when 按钮_清空.Click() {
foreach name in fruits {
动态组件1.Remove(name)
}
}
这些按钮是运行时才有的,设计器里没有它们的「被点击」积木,用「任意按钮.被点击」接事件,
component 就是被点的那个按钮,用取编号(组件)(GetId)知道是哪一个(这里编号就是水果名):
when any Button.Click(component, notAlreadyHandled) {
var fruit = 动态组件1.GetId(component)
if fruit != "" {
标签1.Text = join("已加入购物车:", fruit)
any Button(component).Enabled = false
}
}
用模板一次创建一张卡片
模板是 JSON:components 里每个组件写 id、type、properties,可以用 components 嵌套子组件;
keys 列出占位符,{名字} 会被参数列表里对应的值替换:
when 按钮_添加.Click() {
动态组件1.Schema(垂直布局_容器, 文本输入框_模板.Text, [文本输入框_标题.Text])
}
文本输入框_模板 里的模板示例:
{
"metadata-version": "1",
"name": "card",
"keys": ["title"],
"components": [
{"id": "card_{title}", "type": "HorizontalArrangement", "properties": {"BackgroundColor": "&HFFE3F2FD"},
"components": [
{"id": "label_{title}", "type": "Label", "properties": {"Text": "{title}", "FontSize": "18"}}
]}
]
}
搭建与测试
在设计器拖入本组件和案例涉及的按钮、标签、布局等组件,按案例中的名称重命名。先运行最小案例,确认事件返回,再增加业务逻辑。示例中的素材先上传到项目,服务器地址、令牌、文件路径换成自己的值。
可见组件需要有非零宽高;不可见工具组件必须由属性或方法启动。设计器展示样式不等于运行时已加载数据或绑定目标。联机测试应使用包含本组件的 AI 伴侣;涉及系统入口或权限的行为还要编译安装后验证。
属性、方法与事件速查
完整参数类型、默认值和平台说明见组件参考。下表按调用入口列出用途;有完成事件的方法在事件中读取结果。
| 入口 | 用途 |
|---|---|
版本(Version) |
上游拓展的版本号(11),与原拓展一致。 |
版本名称(VersionName) |
上游拓展的版本名(2.3.1),与原拓展一致。 |
修改编号(编号,新编号)(ChangeId) |
把已创建组件的编号改成新编号(旧编号必须存在、新编号必须未被使用)。注意:所有包含旧编号的编号都会被替换,如把 Timmy 改名时 Timmy-truck 也会变。 |
创建(所在布局,组件类型,编号)(Create) |
在指定布局(或画布)里创建一个新组件,并给它一个编号供以后引用;创建完成触发「组件已创建」。componentName 可以是组件类型名(如 Button)、一个现有组件(创建同类型的新组件,拓展也可以),或完整类名。不能直接创建在屏幕上,要先放一个布局。 |
临时创建(所在布局,组件类型)(CreateEphemeral) |
在指定布局(或画布)里创建一个新组件并返回,不登记编号(用编号相关的积木找不到它)。不能直接创建在屏幕上。 |
立即创建(所在布局,组件类型,编号)(CreateSync) |
立即在指定布局(或画布)里创建一个新组件并直接返回它(同步),同时登记编号;编号留空时自动生成。 |
生成编号(GenerateID) |
生成一个随机的唯一编号(UUID),不关心编号时可用它创建组件。 |
取组件(编号)(GetComponent) |
按编号取回组件;找不到时返回空文本。 |
组件元数据(组件)(GetComponentMeta) |
取指定组件的元数据(类型、类名、分类、描述、版本等),结果是字典。 |
事件元数据(组件)(GetEventMeta) |
取指定组件全部事件的元数据,结果是字典。 |
方法元数据(组件)(GetFunctionMeta) |
取指定组件全部方法的元数据,结果是字典。 |
取编号(组件)(GetId) |
取组件的编号(取回组件的反操作);不是本组件创建的返回空文本。 |
取位置(组件)(GetOrder) |
取组件在所在布局里的位置,从 1 开始;没有所在布局时返回 0。 |
取属性(组件,名称)(GetProperty) |
按属性名读组件的属性值(相当于属性读取积木),值为空时返回空文本。 |
属性元数据(组件)(GetPropertyMeta) |
取指定组件全部属性的元数据和当前值,结果是字典。 |
调用方法(组件,名称,参数列表)(Invoke) |
按方法名调用组件的方法,parameters 是参数列表,返回方法的结果(为空时返回空文本)。不需要结果时用「执行但忽略结果」积木包住。 |
是否动态创建(组件)(IsDynamic) |
组件是否由本组件动态创建。 |
最近用的编号(LastUsedID) |
最近一次创建组件用的编号。 |
移到布局(布局,组件)(Move) |
把组件移到另一个布局里(排在最后)。 |
按编号删除(编号)(Remove) |
按编号删除组件,编号随之注销,可以再用来创建新组件。 |
删除组件(组件)(RemoveComponent) |
从屏幕上删除一个组件(设计时放的组件也可以);如果是动态创建的,同时注销它的编号。 |
替换编号(编号,新编号)(ReplaceId) |
把一个编号精确替换为新编号(只改这一个)。 |
按模板创建(所在布局,模板,参数列表)(Schema) |
按 JSON 模板批量创建组件(可嵌套),模板里的占位符用 parameters 列表的值替换;全部创建完触发「模板已创建」。模板格式见文档。 |
设置位置(组件,索引)(SetOrder) |
设置组件在所在布局里的位置,从 1 开始;设为 0 移到最后。 |
批量设属性(组件,属性字典)(SetProperties) |
用字典一次设置多个属性:键是属性名,值是属性值。 |
设属性(组件,名称,值)(SetProperty) |
按属性名设置组件的属性(相当于属性设置积木),只能在设计器里设的属性也可以。 |
全部编号(UsedIDs) |
本组件创建的全部组件编号(列表)。 |
组件已创建(组件,编号,类别)(ComponentBuilt) |
组件创建完成后触发:component 是新组件,id 是它的编号,type 是组件类型名。 |
模板已创建(名称,参数列表)(SchemaCreated) |
用「按模板创建」创建完一批组件后触发:name 是模板名,parameters 是传入的参数列表。 |
常见问题与验收
| 检查项 | 操作与预期 |
|---|---|
| 初始化 | 对照案例检查是否已经调用加载、注册、连接或显示方法;仅拖入组件不会替你执行这些步骤。 |
| 结果返回 | 将成功事件和失败事件都接到标签,记录事件参数;异步操作完成前不读取结果属性。 |
| 输入配置 | 检查素材名大小写、网址是否为直接资源地址、文件是否存在、编号和索引是否在范围内。 |
| 平台与权限 | 按组件参考中的平台说明测试;授权被拒绝时应有明确提示,不继续假定操作成功。 |
| 最小案例 | 先验证页面中的最小案例,再验证第二个场景;重复操作、取消、返回屏幕后结果应符合事件说明。 |
完整 .aia 源码与操作指导
用动态组件搭建一份可填写和保存的巡检表单。上方是真实动态输入框和设备资料卡,主界面只保留创建、保存、查看记录与添加资料卡;编号管理和接口细节在“表单管理与高级设置”中。
巡检表单与设备资料卡
导入方法:项目 → 导入项目(.aia)→ 选择下载的 .aia 源码文件。 创建可实际填写的巡检输入框,保存内容和时间,重新打开查看上次记录;设备资料卡按模板添加并可点击查看详情。编号、移动、排序等管理功能收进高级设置。 覆盖检查 30/30,正式编辑器首次载入和保存重开均零错误,后台导入与安装包编译通过。真机/伴侣尚未实测。
先运行这个实际案例
- 点击“创建巡检输入框”,在上方输入框填写记录,再点“保存当前巡检记录”。
- 重新打开案例,点“查看上次保存记录”,核对保存时间和内容。动态界面重新创建,本地记录保留。
- 输入资料标题,点“添加设备资料卡”,点击卡片按钮查看实际编号和文字。
- 打开高级设置再学习动态按钮、移动、排序、改名和删除。
高级面板默认收起,原完整功能入口仍可打开使用。源码为中文app.json和Screen1.ai-blocks,AIA包含全部素材和完整积木。正式编辑器、后台导入及安装包检查以更新后的最终归档报告为准;真机/伴侣尚未实测。
| API / 功能 | 操作入口 | 预期结果 |
|---|---|---|
| Thread、Version、VersionName | 设计器Main;启动和读取 | Android使用Main时立即创建,鸿蒙目前同步;版本实际读取 |
| CreateSync、Create、CreateEphemeral、GenerateID、ComponentBuilt | 同步输入框、普通按钮、临时标签 | 真实动态控件;普通按钮用自动编号,事件来自实际创建;临时标签不登记业务编号 |
| GetComponent、GetId、IsDynamic、LastUsedID、UsedIDs、GetProperty | 读取区 | 实际组件/业务编号/文字;临时标签的IsDynamic按登记语义返回假,并非不存在 |
| SetProperty、SetProperties、Invoke | 设置、批量、调用 | 实际文字、字号、背景;调用真实MoveCursorToEnd,无返回结果不能当成功事件 |
| ChangeId、ReplaceId | 新编号输入后分别点对应按钮 | ChangeId替换包含旧编号的子编号,ReplaceId只改当前编号;组件本身仍在,业务编号读回变化 |
| Move、SetOrder、GetOrder | 移到另一栏;先创建普通按钮再移到第一项 | 真实布局移动与1起始顺序;零或越界在鸿蒙移到末尾,不用于本案例 |
| GetComponentMeta、GetEventMeta、GetFunctionMeta、GetPropertyMeta | 元数据 | 实际运行时描述字典,组件类型不同内容不同 |
| Remove、RemoveComponent | 按编号删除输入框、按组件删除临时标签 | 控件真实消失,编号列表读回;不删除其他案例或保存数据 |
| Schema、SchemaCreated | 参数模板卡片、非法空参数 | 真实嵌套布局、标签、按钮;实际模板事件;参数个数不匹配显示错误且不新增卡片 |
| 任意组件点击、输入与恢复 | 动态按钮、输入框实际输入、读取、重开 | 动态按钮详情读实际编号;重新打开清空本次动态界面,无虚构持久化 |
所有返回值均用于界面反馈,错误由底部错误区展示。设计器采用明确非默认配置,初始化与界面同步。API 覆盖检查按最终 AIA 检查方法、事件、属性读取与设置及设计器配置,不能替代真实设备验证。
扫码添加客服咨询