示例
这是一个 @Builder值传参 示例:
@Entry
@Component
struct C_Builder{
@State label:string = "hello builder";
@State hint:string = "";
build() {
Tabs(){
……
TabContent(){
Column() {
overBuilder2(this.label)
Text(this.hint).margin({top:20,bottom:20})
Button('Click me').onClick(() => {
this.label = 'ArkUI';
this.hint = 'Button事件触发,但是overBuilder的内容并未因label的改变而改变 this.label = '+this.label;
})
}.width("100%")
.height("100%")
}.tabBar("值传递")
}
}
}
@Builder function overBuilder2(paramA1: string) {
Row() {
Text(`UseStateVarByReference: ${paramA1} `)
}
}
装饰器使用说明
@BuilderParam装饰器:引用@Builder函数
场景: 当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。
作用: ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指向@Builder方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
帮助理解: 相当于有N个人都要看书,大家都是用眼睛看,但是突然有一个盲人出现了,这个时候用眼睛看书已经不实际了,盲人靠手的触摸看的也是盲文,有点类似与java的重写,但这个允许人不看书。
尾随闭包初始化组件
- 在自定义组件中使用@BuilderParam装饰的属性时也可通过尾随闭包进行初始化。在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。
- 在这个示例进行了展示:
@Component
struct ReadBooks{
@Prop bookType:string ;
@BuilderParam readBook:() => void;
build(){
Column(){
Text(this.bookType)
this.readBook()
}
}
}
@Entry
@Component
struct People{
@State bookType : string = "正常人看正常书";
@State btc :string = "盲人"
build(){
Column(){
Button(this.btc).onClick(()=>{
if (this.btc == "盲人") {
this.bookType = "盲人看盲文";
this.btc = "正常人"
}else {
this.bookType = "正常人看正常书";
this.btc = "盲人"
}
})
ReadBooks({bookType:this.bookType}){
Column(){
Text("看书中……")
}
}
}.width("100%").alignSelf(ItemAlign.Center)
}
}
参数初始化组件
- @BuilderParam装饰的方法可以是有参数和无参数的两种形式,需与指向的@Builder方法类型匹配。@BuilderParam装饰的方法类型需要和@Builder方法类型一致。
@Builder function overBuilder($$ : {label: string }) {
Text($$.label)
.width(400)
.height(50)
.backgroundColor(Color.Green)
}
@Component
struct Child {
label: string = 'Child'
// 无参数类型,指向的componentBuilder也是无参数类型
@BuilderParam customBuilderParam: () => void;
// 有参数类型,指向的GlobalBuilder1也是有参数类型的方法
@BuilderParam customOverBuilderParam: ($$ : { label : string}) => void;
build() {
Column() {
this.customBuilderParam()
this.customOverBuilderParam({label: 'global Builder label' } )
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent'
@Builder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
this.componentBuilder()
Child({ customBuilderParam: this.componentBuilder, customOverBuilderParam: overBuilder })
}
}
}
@Styles装饰器:定义组件重用样式
-
如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在进行重复样式设置,虽然可以复制粘贴,但为了代码简洁性和后续方便维护,我们推出了可以提炼公共样式进行复用的装饰器@Styles。
-
@Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用。通过@Styles装饰器可以快速定义并复用自定义样式。用于快速定义并复用自定义样式。
装饰器使用说明
- 当前@Styles仅支持通用属性和通用事件。
- @Styles方法不支持参数。
- @Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
- 只能在当前文件内使用,不支持export。
- 定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值,注意:组件的onClick优先于@Styles里的onClick,并且只响应优先级高的
- 组件内@Styles的优先级高于全局@Styles。框架优先找当前组件内的@Styles,如果找不到,则会全局查找。
/// 定义在全局的@Styles封装的样式
@Styles function globalFancy () {
.width(150)
.height(100)
.backgroundColor(Color.Pink)
}
@Entry
@Component
struct C_Styles {
@State heightValue: number = 50
// 定义在组件内的@Styles封装的样式
@Styles fancy() {
.width(200)
.height(this.heightValue)
.backgroundColor(Color.Yellow)
.onClick(() => {
if (this.heightValue == 50) {
this.heightValue = 100
}else {
this.heightValue = 50
}
})
}
build() {
Column({ space: 10 }) {
// 使用全局的@Styles封装的样式
Text('FancyA')
.globalFancy()
.fontSize(30)
// 使用组件内的@Styles封装的样式
Text('FancyB')
.fancy()
.fontSize(30)
// 点击C 会发现B的高度发生了改变,也就是当同事引用多个样式时,框架会对其取并集
Text('FancyC')
.fancy()
.globalFancy()
.fontSize(30)
Button("测试")
.fancy()
.fontColor(Color.Black)
.fontSize(30)
.onClick(()=>{
AlertDialog.show({
title:"事件",
message:"测试按钮事件触发"
})
})
}
}
}
@Extend装饰器:定义扩展组件样式
在前文的示例中,可以使用@Styles用于样式的扩展,在@Styles的基础上,华为提供了@Extend,用于扩展原生组件样式。
语法
@Extend(UIComponentName) function functionName { ... }
使用规则
- 和@Styles不同,@Extend仅支持定义在全局,不支持在组件内部定义。
- 和@Styles不同,@Extend支持封装指定的组件的私有属性和私有事件和预定义相同组件的@Extend的方法。
- 和@Styles不同,@Extend装饰的方法支持参数,开发者可以在调用时传递参数,调用遵循TS方法传值调用。
- @Extend装饰的方法的参数可以为function,作为Event事件的句柄。
- @Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染。
示例
// @Extend(Text)可以支持Text的私有属性fontColor
@Extend(Text) function fancy () {
.fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy
@Extend(Text) function superFancyText(size:number) {
.fontSize(size)
.fancy()
}
//@Extend装饰的方法的参数可以为function,作为Event事件的句柄。
@Extend(Text) function makeMeClick(onClick: () => void) {
.backgroundColor(Color.Grey)
.onClick(onClick)
}
@Entry
@Component
struct FancyUse {
@State label: string = 'Hello World';
@State label2: string = 'Hello World';
@State fontSizeValue: number = 30
onClickHandler() {
if (this.label.includes('World')) {
this.label = 'Hello ArkUI';
}else {
this.label = 'Hello World';
}
}
build() {
Column({ space: 10 }) {
Text('Fancy0')
.fancy()
Text('Fancy1')
.superFancyText(24)
Text('Fancy2')
.superFancyText(28)
Text('Fancy3')
.superFancyText(this.fontSizeValue)
.onClick(()=>{
if (this.fontSizeValue == 30) {
this.fontSizeValue = 35;
}else {
this.fontSizeValue = 30;
}
})
Text(`${this.label}`)
//this.onClickHandler.bind(this) 是用来绑定 FancyUse 组件实例的 onClickHandler 方法的,以确保在 onClickHandler 方法中 this 的指向正确。
//然后,这个绑定后的函数作为参数传递给了 makeMeClick 方法,使得当 Text 组件被点击时,会调用 onClickHandler 方法,并且在正确的上下文中执行。
.makeMeClick(this.onClickHandler.bind(this))
// 优先组件的onClick,且只响应优先级别高的
Text(`${this.label2}`)
.makeMeClick(this.onClickHandler.bind(this))
.onClick(()=>{
this.label2 = 'Hello onClick';
})
}.width("100%")
}
}
stateStyles:多态样式
stateStyles(又称为:多态样式)针对:@Styles和@Extend仅仅应用于静态页面的样式复用,stateStyles可以依据组件的内部状态的不同,快速设置不同样式。
概述
stateStyles是属性方法,可以根据UI内部状态来设置样式,类似于css伪类,但语法不同。ArkUI提供以下四种状态:
- focused:获焦态。
- normal:正常态。
- pressed:按压态。
- disabled:不可用态。
示例
//在stateStyles里不能进行引用,会报错:.stateStyles doesn't conform standard.
@Styles function normalStyle(){
.backgroundColor(Color.Gray)
}
@Extend(Text) function normalExtend(size:number){
.fontSize(size)
}
@Entry
@Component
struct C_stateStyles{
@Styles pressedStyle() {
.backgroundColor(Color.Red)
}
@Styles normalStyle(){
.backgroundColor(Color.Gray)
}
build(){
Column() {
Button('Button1')
.stateStyles({
focused: {
.backgroundColor(Color.Pink)
},
pressed: {
.backgroundColor(Color.Black)
},
normal: {
.backgroundColor(Color.Red)
}
})
.margin(20)
Button('Button2')
.stateStyles({
pressed:this.pressedStyle,
normal:this.normalStyle
})
}.margin('30%')
}
}