鸿蒙开发—学习声明式UI

基本UI描述

ArkTS通过装饰器@Component和@Entry装饰struct关键字声明的数据结构,构成一个自定义组件。自定义组件中提供了一个build函数,开发者需在该函数内以链式调用的方式进行基本的UI描述,UI描述的方法请参考UI描述规范。

基本概念

  • struct:自定义组件可以基于struct实现,不能有继承关系,对于struct的实例化,可以省略new。
  • 装饰器:装饰器给被装饰的对象赋予某一种能力,其不仅可以装饰类或结构体,还可以装饰类的属性。多个装饰器可以叠加到目标元素上,定义在同一行中或者分开多行,推荐分开多行定义。
less复制代码@Entry
@Component
struct MyComponent {
}
  • build函数:自定义组件必须定义build函数,并且禁止自定义构造函数。build函数满足Builder构造器接口定义,用于定义组件的声明式UI描述。
typescript复制代码interface Builder {build: () => void
}
  • @Component:装饰struct,结构体在装饰后具有基于组件的能力,需要实现build方法来创建UI。
  • @Entry: 装饰struct,组件被装饰后作为页面的入口,页面加载时将被渲染显示。
  • @Preview:装饰struct, 用@Preview装饰的自定义组件可以在DevEco Studio的预览器上进行实时预览,加载页面时,将创建并显示@Preview装饰的自定义组件。

说明: 在单个源文件中,最多可以使用10个@Preview装饰自定义组件,更多说明请参考查看ArkTS组件预览效果。

  • 链式调用:以 “.” 链式调用的方式配置UI组件的属性方法、事件方法等。

UI描述规范

无参数构造配置

如果组件的接口定义中不包含必选构造参数,组件后面的“()”中不需要配置任何内容。例如,Divider组件不包含构造参数:

scss复制代码Column() {Text('item 1')Divider()Text('item 2')
}

有参数构造配置

如果组件的接口定义中包含构造参数,则在组件后面的“()”中可配置相应参数,参数可以使用常量进行赋值。

例如:

  • Image组件的必选参数src:
rust
复制代码Image('https://xyz/test.jpg')
  • Text组件的参数content,该参数非必选,即配置或不配置均可:
scss
复制代码Text('test')

变量或表达式也可以用于参数赋值,其中表达式返回的结果类型必须满足参数类型要求,变量的定义详见页面级变量的状态管理与应用级变量的状态管理。例如,设置变量或表达式来构造Image和Text组件的参数:

kotlin复制代码Image(this.imagePath)
Image('https://' + this.imageUrl)
Text(`count: ${this.count}`)

属性配置

使用属性方法配置组件的属性,属性方法紧随组件,并用"."运算符连接。

  • 配置Text组件的字体大小属性:
scss复制代码Text('test').fontSize(12)
  • 使用"."运算符进行链式调用并同时配置组件的多个属性,如下所示:
scss复制代码Image('test.jpg').alt('error.jpg')    .width(100)    .height(100)
  • 除了直接传递常量参数外,还可以传递变量或表达式,如下所示:
kotlin复制代码Text('hello').fontSize(this.size)
Image('test.jpg').width(this.count % 2 === 0 ? 100 : 200)    .height(this.offset + 100)
  • 对于系统内置组件,框架还为其属性预定义了一些枚举类型供开发人员调用,枚举类型可以作为参数传递,且必须满足参数类型要求。例如,可以按以下方式配置Text组件的颜色和字体属性:
scss复制代码Text('hello').fontSize(20).fontColor(Color.Red).fontWeight(FontWeight.Bold)

事件配置

通过事件方法可以配置组件支持的事件,事件方法紧随组件,并用"."运算符连接。

  • 使用lambda表达式配置组件的事件方法:
javascript复制代码Button('add counter').onClick(() => {this.counter += 2})
  • 使用匿名函数表达式配置组件的事件方法,要求使用bind,以确保函数体中的this引用包含的组件:
javascript复制代码Button('add counter').onClick(function () {this.counter += 2}.bind(this))
  • 使用组件的成员函数配置组件的事件方法:
kotlin复制代码myClickHandler(): void {this.counter += 2
}
​
...
​
Button('add counter').onClick(this.myClickHandler.bind(this))

子组件配置

对于支持子组件配置的组件,例如容器组件,在"{ … }"里为组件添加子组件的UI描述。Column、Row、Stack、Grid、List等组件都是容器组件。

  • 以下是简单的Column示例:
scss复制代码Column() {Text('Hello').fontSize(100)Divider()Text(this.myText).fontSize(100).fontColor(Color.Red)
}
  • 容器组件之间也可以互相嵌套,实现相对复杂的多级嵌套效果:
scss复制代码Column() {Row() {Image('test1.jpg').width(100).height(100)Button('click +1').onClick(() => {console.info('+1 clicked!')})}
​Divider()Row() {Image('test2.jpg').width(100).height(100)Button('click +2').onClick(() => {console.info('+2 clicked!')})}
​Divider()Row() {Image('test3.jpg').width(100).height(100)Button('click +3').onClick(() => {console.info('+3 clicked!')})}
}

动态构建UI元素

基本UI描述介绍的是如何创建一个内部UI结构固定的自定义组件,为了满足开发者自定义组件内部UI结构的需求,ArkTS同时提供了动态构建UI元素的能力。

@Builder

可通过@Builder装饰器进行描述,该装饰器可以修饰一个函数,此函数可以在build函数之外声明,并在build函数中或其他@Builder修饰的函数中使用,从而实现在一个自定义组件内快速生成多个布局内容。使用方式如下面示例所示。

kotlin复制代码// xxx.ets
@Component
struct CompB {@State CompValue: string = ''
​aboutToAppear() {console.info('CompB aboutToAppear.')}
​aboutToDisappear() {console.info('CompB aboutToDisappear.')}
​build() {Column() {Button(this.CompValue).margin(5)}}
}
​
@Entry
@Component
struct CompA {size1: number = 100@State CompValue1: string = "Hello,CompValue1"@State CompValue2: string = "Hello,CompValue2"@State CompValue3: string = "Hello,CompValue3"
​// @Builder装饰的函数CompC内使用自定义组件CompB@Builder CompC(value: string) {CompB({ CompValue: value })}
​@Builder SquareText(label: string) {Text(label).fontSize(18).width(1 * this.size1).height(1 * this.size1)}
​// @Builder装饰的函数RowOfSquareTexts内使用@Builder装饰的函数SquareText@Builder RowOfSquareTexts(label1: string, label2: string) {Row() {this.SquareText(label1)this.SquareText(label2)}.width(2 * this.size1).height(1 * this.size1)}
​build() {Column() {Row() {this.SquareText("A")this.SquareText("B")}.width(2 * this.size1).height(1 * this.size1)
​this.RowOfSquareTexts("C", "D")Column() {// 使用三次@Builder装饰的自定义组件this.CompC(this.CompValue1)this.CompC(this.CompValue2)this.CompC(this.CompValue3)}.width(2 * this.size1).height(2 * this.size1)}.width(2 * this.size1).height(2 * this.size1)}
}

@BuilderParam8+

@BuilderParam装饰器用于修饰自定义组件内函数类型的属性(例如:@BuilderParam noParam: () => void),并且在初始化自定义组件时被@BuilderParam修饰的属性必须赋值。

引入动机 当开发者创建自定义组件,并想对该组件添加特定功能时(例如在自定义组件中添加一个点击跳转操作)。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,引入了@BuilderParam装饰器,此装饰器修饰的属性值可为@Builder装饰的函数,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。

参数初始化组件

通过参数初始化组件时,将@Builder装饰的函数赋值给@BuilderParam修饰的属性,并在自定义组件内调用该属性值。若@BuilderParam修饰的属性在进行赋值时不带参数(如:noParam: this.specificNoParam),则此属性的类型需定义为无返回值的函数(如:@BuilderParam noParam: () => void);若带参数(如:withParam: this.SpecificWithParam(‘WithParamA’)),则此属性的类型需定义成any(如:@BuilderParam withParam: any)。

scss复制代码// xxx.ets
@Component
struct CustomContainer {header: string = ''@BuilderParam noParam: () => void@BuilderParam withParam: anyfooter: string = ''
​build() {Column() {Text(this.header).fontSize(30)this.noParam()this.withParam()Text(this.footer).fontSize(30)}}
}
​
@Entry
@Component
struct CustomContainerUser {@Builder specificNoParam() {Column() {Text('noParam').fontSize(30)}}
​@Builder SpecificWithParam(label: string) {Column() {Text(label).fontSize(30)}}
​build() {Column() {CustomContainer({header: 'HeaderA',noParam: this.specificNoParam,withParam: this.SpecificWithParam('WithParamA'),footer: 'FooterA'})Divider().strokeWidth(3).margin(10)CustomContainer({header: 'HeaderB',noParam: this.specificNoParam,withParam: this.SpecificWithParam('WithParamB'),footer: 'FooterB'})}}
}

尾随闭包初始化组件

在自定义组件中使用@BuilderParam修饰的属性时也可通过尾随闭包进行初始化(在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景(CustomContainer(){})。开发者可把尾随闭包看做一个容器,向其中填充内容,如在闭包内增加组件({Column(){…}),闭包内语法规范与build函数一致。此场景下自定义组件内有且仅有一个使用@BuilderParam修饰的属性。

示例:在闭包内添加Column组件并设置点击事件,在Column组件内调用@Builder修饰的specificParam函数,点击Column组件后将自定义组件CustomContainer中header的属性值由“header”改变为“changeHeader”。在初始化自定义组件CustomContainer时,尾随闭包的内容会被赋值给@BuilderParam修饰的closer属性。

scss复制代码// xxx.ets
@Component
struct CustomContainer {header: string = ''@BuilderParam closer: () => void
​build() {Column() {Text(this.header).fontSize(30)this.closer()}}
}
​
@Builder function specificParam(label1: string, label2: string) {Column() {Text(label1).fontSize(30)Text(label2).fontSize(30)}
}
​
@Entry
@Component
struct CustomContainerUser {@State text: string = 'header'
​build() {Column() {CustomContainer({header: this.text,}) {Column() {specificParam('testA', 'testB')}.backgroundColor(Color.Yellow).onClick(() => {this.text = 'changeHeader'})}}}
}

@Styles

ArkTS为了避免开发者对重复样式的设置,通过@Styles装饰器可以将多个样式设置提炼成一个方法,直接在组件声明时调用,通过@Styles装饰器可以快速定义并复用自定义样式。当前@Styles仅支持通用属性。

@Styles可以定义在组件内或组件外,在组件外定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。

scss复制代码// xxx.ets
@Styles function globalFancy () {.width(150).height(100).backgroundColor(Color.Pink)
}
​
@Entry
@Component
struct FancyUse {@Styles componentFancy() {.width(100).height(200).backgroundColor(Color.Yellow)}
​build() {Column({ space: 10 }) {Text('FancyA').globalFancy().fontSize(30)Text('FancyB').globalFancy().fontSize(20)Text('FancyC').componentFancy().fontSize(30)Text('FancyD').componentFancy().fontSize(20)}}
}

@Styles还可以在StateStyles属性内部使用,在组件处于不同的状态时赋予相应的属性。

在StateStyles内可以直接调用组件外定义的@Styles方法,但需要通过this关键字调用组件内定义的@Styles方法。

less复制代码// xxx.ets
@Styles function globalFancy () {.width(120).height(120).backgroundColor(Color.Green)
}
​
@Entry
@Component
struct FancyUse {@Styles componentFancy() {.width(80).height(80).backgroundColor(Color.Red)}
​build() {Row({ space: 10 }) {Button('Fancy').stateStyles({normal: {.width(100).height(100).backgroundColor(Color.Blue)},disabled: this.componentFancy,pressed: globalFancy})}}
}

@Extend

@Extend装饰器将新的属性方法添加到Text、Column、Button等内置组件上,通过@Extend装饰器可以快速地扩展原生组件。@Extend不能定义在自定义组件struct内。

less复制代码// xxx.ets
@Extend(Text) function fancy (fontSize: number) {.fontColor(Color.Red).fontSize(fontSize).fontStyle(FontStyle.Italic).fontWeight(600)
}
​
@Entry
@Component
struct FancyUse {build() {Row({ space: 10 }) {Text("Fancy").fancy(16)Text("Fancy").fancy(24)Text("Fancy").fancy(32)}}
}

说明:

  • @Extend装饰器不能定义在自定义组件struct内。
  • @Extend装饰器内仅支持属性方法设置。

@CustomDialog

@CustomDialog装饰器用于装饰自定义弹窗组件,使得弹窗可以动态设置内容及样式。

scss复制代码// xxx.ets
@CustomDialog
struct DialogExample {controller: CustomDialogControlleraction: () => void
​build() {Row() {Button('Close CustomDialog').onClick(() => {this.controller.close()this.action()})}.padding(20)}
}
​
@Entry
@Component
struct CustomDialogUser {dialogController: CustomDialogController = new CustomDialogController({builder: DialogExample({ action: this.onAccept }),cancel: this.existApp,autoCancel: true});
​onAccept() {console.info('onAccept');}
​existApp() {console.info('Cancel dialog!');}
​build() {Column() {Button('Click to open Dialog').onClick(() => {this.dialogController.open()})}}
}

插件分享

1.Chinese

汉化插件,让国人开发者更加如鱼得水

2.Atom Material File Icons

提供文件和文件夹图标支持,让你的项目看的更加赏心悦目

3.One Dark theme

一款暗色系主题插件,非常适合在晚上偷偷卷代码

4.Material Theme UI

一款多色系主题插件,自2021年后需要收费使用,本节文末提供下载链接

5.Rainbow Brackets

括号匹配彩虹色

6.Indent Rainbow

代码缩进提供色彩支持,非常适合控制代码格式

本文主要简单解析了在鸿蒙开发当中,声明式UI讲解。有更多的鸿蒙开发学习,可以查看《鸿蒙开发者进阶》点击可以查看详细的内容板块。

以上为一张学习路线略缩图,高清完整版请移至主业查看获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/213116.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GZ029 智能电子产品设计与开发赛题第4套

2023年全国职业院校技能大赛高职组 “GZ029智能电子产品设计与开发”赛项赛卷四 题目:模拟工业传送带物品检测系统的设计与开发 1 竞赛任务 在智能电视机上播放工业传送带传输物品视频,模拟工业传送带物品检测系统(以下简称物品检测系统&…

DALI1.0学习——BIT解码

最近在学习DALI调光相关知识并下载了Microchip提供的基于ATMega88PA的软件工程及硬件设计参考方案。写这些文章的目的就是把自己对知识的理解作一些梳理。 芯片厂果然专业,考虑得相当周到,为了芯片销量连软件和硬件方案全都提供了。芯片厂关于DALI1.0实…

【unity小技巧】实现枪武器随镜头手臂摇摆效果

文章目录 前言方法一、改变武器位置方法二、改变武器旋转结语完结 前言 如果我们视角移动转向,武器如果不跟着进行摇摆,会感觉我们的动作很生硬,特别是射击类游戏,如下 实现武器摇摆这里主要分享两种实现方法,一种是…

SSD数据在写入NAND之前为何要随机化?-Part1

SSD的存储介质是什么,它就是NAND闪存。那你知道NAND闪存是怎么工作的吗?其实,它就是由很多个晶体管组成的。这些晶体管里面存储着电荷,代表着我们的二进制数据,要么是“0”,要么是“1”。NAND闪存原理上是一…

0基础学java-day14-(集合)

一、集合 前面我们保存多个数据使用的是数组,那么数组有不足的地方,我们分析一下 1.数组 2 集合 数据类型也可以不一样 3.集合的框架体系 Java 的集合类很多,主要分为两大类,如图 :[背下来] package com.hspedu.c…

设计模式之GoF23介绍

深入探讨设计模式:构建可维护、可扩展的软件架构 一、设计模式的背景1.1 什么是设计模式1.2 设计模式的历史 二、设计模式的分类2.1 创建型模式2.2 结构型模式2.3 行为型模式 三、七大设计原则四、设计模式关系结论 :rocket: :rocket: :rocket: 在软件开发领域&…

算法:爬楼梯(迭代和动态规划)

迭代 时间复杂度 O(n) 空间复杂度 O(1) /*** param {number} n* return {number}*/ var climbStairs function(n) {let l 0, r 0 , sum 1for(let i1; i<n; i){l rr sumsum l r}return sum }; 动态规划 时间复杂度 O(n) 空间复杂度 O(n) /*** param {number} n* r…

【密码学基础】Diffie-Hellman密钥交换协议

DH介绍 Diffie-Hellman密钥协议算法是一种确保共享密钥安全穿越不安全网络的方法。 这个机制的巧妙在于需要安全通信的双方可以用这个方法确定对称密钥&#xff0c;然后可以用这个密钥进行加密和解密。 但是注意&#xff0c;这个密钥交换协议 只能用于密钥的交换&#xff0c;而…

Java面试题(每天10题)-------连载(45)

Dubbo篇 1、Dubbo的服务调用流程 2、Dubbo支持那种协议&#xff0c;每种协议的应用场景&#xff0c;优缺点&#xff1f; dubbo&#xff1a; 单一长连接和 NIO 异步通讯&#xff0c;适合大并发小数据量的服务调用&#xff0c;以及消费者远大于提供者。传输协议 TCP&#xff0c;…

Proteus仿真--射击小游戏仿真设计

本文介绍基于proteus射击小游戏仿真设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 K1-K4为4个按键&#xff0c;用于上移、下移、确认等&#xff0c;模拟单机游戏 仿真运行视频 Proteus仿真--射击小游戏仿真设计 附完整Proteus仿真资料代码资料 …

ArcGIS界面显示分辨率调整

因为电脑显示分辨率的问题呢&#xff0c;ArcGIS的界面显示会字体显示不合适&#xff0c;出现模糊情况&#xff0c;这时候只需要做个简单的操作设置一下便可以解决&#xff01; 1、右键ArcMap的快捷启动方式。 2、对应选择兼容性——>更高DPI设置——>勾选替代DPI缩放行为…

体系化学习运筹学基础算法的实践和总结

文章目录 引言目标设计目标实践文章汇总经验总结一则预告 引言 眨眼间已经12月了&#xff0c;眼看着2023年马上要过完了。 女朋友最近总说&#xff0c;工作以后感觉时间过的好快。事实上&#xff0c;我也是这么认为的。年纪越大&#xff0c;越会担心35岁危机的降临。所以&…

Xubuntu16.04系统中使用EDIMAX EW-7822UAC无线网卡开启5G自发AP

目录 1.关于 EDIMAX EW-7822UAC2.驱动安装3.查看无线网卡信息3.通过create_ap配置5G自发AP 1.关于 EDIMAX EW-7822UAC 官网介绍 https://www.edimax.com/edimax/merchandise/merchandise_detail/data/edimax/global/wireless_adapters_ac1200_dual-band/ew-7822uac/ 详细参数…

Python开发运维:Python项目发布到K8S集群

目录 一、实验 1.Python项目发布到K8S集群 一、实验 1.Python项目发布到K8S集群 &#xff08;1&#xff09;获取应用程序代码 #把hello-python.tar.gz压缩包上传到k8s控制节点master1的root下&#xff0c;手动解压 tar zxvf hello-python.tar.gz &#xff08;2&#xff0…

【Linux】进程周边001之进程概念

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.基本概念 2.描述进程-PCB…

LeetCode5.最长回文子串

昨天和之前打比赛的队友聊天&#xff0c;他说他面百度面到这道算法题&#xff0c;然后他用暴力法解的&#xff0c;面试官让他优化他没优化出来&#xff0c;这道题我之前没写过&#xff0c;我就想看看我能不能用效率高一点的方法把它做出来&#xff0c;我一开始就在想用递归或者…

设计CPU功能的数字电路

实验目的(1)熟悉Multisim 电路仿真软件的操作界面和功能; (2)掌握逻辑电路综合设计,并采用仿真软件进行仿真。 实验内容1.试设计一个简易CPU功能的数字电路,实验至少要求采用4个74HC/HCT194作为4个存储单元(可以预先对存储单元存储数据),74HC283作为计算单元。请实现…

多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现RIME-CNN-LSTM-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现RIME-CNN-…

idea本地调试hadoop 遇到的几个问题

1.DEA对MapReduce的toString调用报错&#xff1a;Method threw ‘java.lang.IllegalStateException‘ exception. Cannot evaluate org.apache.hadoop.mapreduc 解决方法&#xff1a;关闭 IDEA 中的启用“ tostring() ”对象视图 2.代码和hdfs路径都对的情况下&#xff0c;程序…

架构设计系列之基础:初探软件架构设计

11 月开始突发奇想&#xff0c;想把自己在公司内部做的技术培训、平时的技术总结等等的内容分享出来&#xff0c;于是就开通了一个 Wechat 订阅号&#xff08;灸哥漫谈&#xff09;&#xff0c;开始同步发送内容。 今天&#xff08;12 月 10 日&#xff09;也同步在 CSDN 上开通…