【HarmonyOS】鸿蒙开发中所使用的装饰器

打印 上一主题 下一主题

主题 707|帖子 707|积分 2121

1. 总结

关键字描述@Builder轻量级的UI元素复用机制@BuilderParam引用@Builder函数,类似于solt插槽wrapBuilder封装@Builder函数为对象,可以组件内举行通报@Styles定义组件的重用样式 |@Extend扩展组件的样式stateStyles多态样式,类似CSS伪类@AnimatableExtend定义可动画属性@Require校验组件构造传参 2. @Builder装饰器

之前了解过自定义组件,自定义组件内部的UI布局固定,仅与使用方举行数据通报,如果我们有一个简朴的样式需要复用,但弄成一个自定义组件就会比较重。以是ArkUI提供了一种更轻量的UI元素复用机制:@Builder。
@Builder所装饰的函数依照build()函数语法规则,可以将重复使用的UI元素抽象成一个方法,在build()方法里举行调用。
被@Builder装饰的函数称为:自定义构建函数。
   build()方法里只能调用 @Builder装饰的自定义构建函数。
  2.1 自定义组件内自定义构建函数

根本使用:
  1. // 定义语法
  2. @Builder MyBuilderFunction(){ ... }
  3. // 使用方法
  4. this.MyBuilderFunction()
复制代码


  • 只能在组件内部使用该自定义构建函数;
  • 自定义构建函数写法和build()相同,this指向当前组件,可以直接使用组件的状态变量,不需要通过状态通报;
2.2 全局自定义构建函数

根本使用:
  1. // 定义语法
  2. @Builder function MyGlobalBuilderFunction(){ ... }
  3. // 使用方法
  4. MyGlobalBuilderFunction()
复制代码


  • 全局定义的构建函数可以被整个应用获取,不允许使用this和bind方法;
  • 如果不涉及组件状态变革,建议使用全局的自定义构建方法;
2.3 参数通报规则

自定义构建函数的参数通报分为按值通报和按引用通报,服从以下规则:


  • 参数的类型必须与参数声明的类型一致,不允许undefined null和返回 undefined null的表达式;
  • 自定义构造函数内部,不允许改变参数值。如果要改变参数值,且同步回调用点,使用@Link;
  • @Builder内UI语法依照UI语法规则;
  • 只有传入一个参数,且参数需要直接传入对象字面量才会按引用通报该参数,其余方式均按值通报;
按引用通报参数: 按引用通报参数时,通报的参数可为状态变量,状态变量的改变会引起@Builder方法内的UI刷新:
  1. class Tmp {
  2.   paramA1: string = ''
  3.   paramB1: string = ''
  4. }
  5. @Builder function overBuilder(params : Tmp) {...}
复制代码
示例:
  1. class Tmp {
  2.   paramA1: string = ''
  3. }
  4. @Builder function overBuilder(params: Tmp) {
  5.   Row() {
  6.     Text(`UseStateVarByReference: ${params.paramA1} `)
  7.   }
  8. }
  9. @Entry
  10. @Component
  11. struct Parent {
  12.   @State label: string = 'Hello';
  13.   build() {
  14.     Column() {
  15.       // Pass the this.label reference to the overBuilder component when the overBuilder component is called in the Parent component.
  16.       // 传递的是状态变量
  17.       overBuilder({ paramA1: this.label })
  18.       Button('Click me').onClick(() => {
  19.         // After Click me is clicked, the UI text changes from Hello to ArkUI.
  20.         this.label = 'ArkUI';
  21.       })
  22.     }
  23.   }
  24. }
复制代码
按引用通报参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用通报参数的范式:
  1. class Tmp {
  2.   paramA1: string = ''
  3.   paramB1: string = ''
  4. }
  5. @Builder function overBuilder($$ : Tmp) {...}
复制代码
示例:
  1. class Tmp {
  2.   paramA1: string = ''
  3. }
  4. @Builder function overBuilder($$: Tmp) {
  5.   Row() {
  6.     Column() {
  7.       Text(`overBuilder===${$$.paramA1}`)
  8.       // @Builder中又调用自定义组件,这里使用$$传递引用
  9.       HelloComponent({message: $$.paramA1})
  10.     }
  11.   }
  12. }
  13. @Component
  14. struct HelloComponent {
  15.   @Link message: string; // 还会建立双向绑定
  16.   build() {
  17.     Row() {
  18.       Text(`HelloComponent===${this.message}`)
  19.       Button("change")
  20.         .onClick(()=>{
  21.           // 点击这里的时候会改变两个Text的文本
  22.           this.message = "Change in the HelloComponent"
  23.         })
  24.     }
  25.   }
  26. }
  27. @Entry
  28. @Component
  29. struct Index {
  30.   @State label: string = 'Hello';
  31.   build() {
  32.     Column() {
  33.       // Pass the this.label reference to the overBuilder component when the overBuilder component is called in the Parent component.
  34.       overBuilder({paramA1: this.label})
  35.       Button('Click me').onClick(() => {
  36.         // After Click me is clicked, the UI text changes from Hello to ArkUI.
  37.         this.label = 'ArkUI';
  38.       })
  39.     }
  40.   }
  41. }
复制代码
按值通报参数: 调用@Builder装饰的函数默认按值通报。当通报的参数为状态变量时,状态变量的改变不回引起@Builder方法内的UI刷新,以是如果使用状态变量时,保举使用引用通报:
  1. @Builder function overBuilder(paramA1: string) {
  2.   Row() {
  3.     Text(`UseStateVarByValue: ${paramA1} `)
  4.   }
  5. }
  6. @Entry
  7. @Component
  8. struct Parent {
  9.   @State label: string = 'Hello';
  10.   build() {
  11.     Column() {
  12.       overBuilder(this.label)
  13.     }
  14.   }
  15. }
复制代码
2. @BuilderParam装饰器:引用@Builder函数

当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作,若直接在组件内嵌入变乱方法,将会导致全部引入该自定义组件的地方均增加了该功能。
为了办理这个问题,ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指向@Builder方法的变量,开发者可以在初始化自定义组件时对此属性赋值,为自定义组件增加特定的功能。该装饰器用于声明恣意UI描述的一个元素,类似slot占位符。
   上面是来自官方文档的先容,其实就是类似于Vue框架的插槽slot。比如我们封装一个列表CellItem组件时,右边大概是箭头、Switch开关、文字等等,对于右边这部分内容,就可以使用@BuilderParam,让父组件定义CellItem组件右边的显示内容,把这部分内容“传”进去。
  2.1 @BuilderParam的使用

@BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化,如果在API 11中和@Require结合使用,则必须父组件构造传参。
下面看一个简朴的使用示例:
  1. @Component
  2. struct Child {
  3.   // 这个自定义构建函数只是为了本地初始化customBuilderParam
  4.   @Builder customBuilder() {}
  5.   
  6.   // 会使用父组件@Builder装饰的方法初始化子组件的@BuilderParam,会覆盖这里的本地初始化
  7.   @BuilderParam customBuilderParam: () => void = this.customBuilder;
  8.   build() {
  9.     Column() {
  10.       // 展示父组件@Builder中的内容
  11.       this.customBuilderParam()
  12.     }
  13.   }
  14. }
  15. @Entry
  16. @Component
  17. struct Parent {
  18.   // 父组件中定义的自定义构建函数
  19.   @Builder componentBuilder() {
  20.     Text(`Parent builder `)
  21.   }
  22.   build() {
  23.     Column() {
  24.       // 将自定义构建函数传递给子组件
  25.       Child({ customBuilderParam: this.componentBuilder })
  26.     }
  27.   }
  28. }
复制代码
示例效果图:

2.2 @BuilderParam和自定义构建函数参数要统一

@BuilderParam装饰的方法可以是有参数和无参数的两种形式,需与指向的@Builder方法类型匹配。@BuilderParam装饰的方法类型需要和@Builder方法类型一致。
  1. class Tmp{
  2.   label:string = ''
  3. }
  4. // 全局的自定义构建函数
  5. @Builder function overBuilder($$ : Tmp) {
  6.   Text($$.label)
  7.     .width(400)
  8.     .height(50)
  9.     .backgroundColor(Color.Green)
  10. }
  11. @Component
  12. struct Child {
  13.   label: string = 'Child'
  14.   @Builder customBuilder() {}
  15.   // 无参数类型,指向的componentBuilder也是无参数类型
  16.   @BuilderParam customBuilderParam: () => void = this.customBuilder;
  17.   
  18.   // 有参数类型,指向的overBuilder也是有参数类型的方法
  19.   @BuilderParam customOverBuilderParam: ($$ : Tmp) => void = overBuilder;
  20.   build() {
  21.     Column() {
  22.       this.customBuilderParam()
  23.       // 调用时传递了参数
  24.       this.customOverBuilderParam({label: 'global Builder label' } )
  25.     }
  26.   }
  27. }
  28. @Entry
  29. @Component
  30. struct Parent {
  31.   label: string = 'Parent'
  32.   @Builder componentBuilder() {
  33.     Text(`${this.label}`)
  34.   }
  35.   build() {
  36.     Column() {
  37.       this.componentBuilder()
  38.       Child({ customBuilderParam: this.componentBuilder, customOverBuilderParam: overBuilder })
  39.     }
  40.   }
  41. }
复制代码
示例效果图:

2.3 this指向问题

  1. @Component
  2. struct Child {
  3.   label: string = `Child`
  4.   @Builder customBuilder() {}
  5.   @Builder customChangeThisBuilder() {}
  6.   
  7.   @BuilderParam customBuilderParam: () => void = this.customBuilder;
  8.   @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
  9.   build() {
  10.     Column() {
  11.       this.customBuilderParam()
  12.       this.customChangeThisBuilderParam()
  13.     }
  14.   }
  15. }
  16. @Entry
  17. @Component
  18. struct Parent {
  19.   label: string = `Parent`
  20.   @Builder componentBuilder() {
  21.     // 需要注意这里的this指向
  22.     Text(`${this.label}`)
  23.   }
  24.   build() {
  25.     Column() {
  26.       // 直接调用组件内的自定义构建函数,this指向Parent组件;
  27.       this.componentBuilder()
  28.       // customBuilderParam,this指向child组件;
  29.       // customChangeThisBuilderParam:箭头函数的this指向的是宿主对象,这里也是Parent组件;
  30.       Child({ customBuilderParam: this.componentBuilder, customChangeThisBuilderParam: ():void=>{this.componentBuilder()} })
  31.     }
  32.   }
  33. }
复制代码
效果图:

2.4 尾随闭包

我们在使用Column Row等容器类组件时,会在 { } 中写子组件,这就是尾随闭包。可以将尾随闭包内的内容看做@Builder装饰的函数传给@BuilderParam:
  1. @Component
  2. struct CustomContainer {
  3.   @Prop header: string = '';
  4.   @Builder closerBuilder(){}
  5.   
  6.   // 使用父组件的尾随闭包{}(@Builder装饰的方法)初始化子组件@BuilderParam
  7.   @BuilderParam closer: () => void = this.closerBuilder
  8.   build() {
  9.     Column() {
  10.       Text(this.header)
  11.         .fontSize(30)
  12.       this.closer()
  13.     }
  14.   }
  15. }
  16. @Builder function specificParam(label1: string, label2: string) {
  17.   Column() {
  18.     Text(label1)
  19.       .fontSize(30)
  20.     Text(label2)
  21.       .fontSize(30)
  22.   }
  23. }
  24. @Entry
  25. @Component
  26. struct CustomContainerUser {
  27.   @State text: string = 'header';
  28.   build() {
  29.     Column() {
  30.       // 创建CustomContainer,在创建CustomContainer时,通过其后紧跟一个大括号“{}”形成尾随闭包
  31.       // 作为传递给子组件CustomContainer @BuilderParam closer: () => void的参数
  32.       CustomContainer({ header: this.text }) {
  33.         Column() {
  34.           specificParam('testA', 'testB')
  35.         }.backgroundColor(Color.Yellow)
  36.         .onClick(() => {
  37.           this.text = 'changeHeader';
  38.         })
  39.       }
  40.     }
  41.   }
  42. }
复制代码
效果图:

需要注意:


  • 使用尾随闭包的自定义组件内部有且仅有一个使用@BuilderParam装饰的属性;
  • 此场景下自定义组件不支持通用属性;
3. wrapBuilder: 封装全局@Builder

全局@Builder作为wrapBuilder的参数返回WrappedBuilder对象,实现全局@Builder可以举行赋值和通报。
   上面是官方的解释,简朴理解就是可以通过wrapBuilder函数将全局的@Builder函数封装成WrappedBuilder对象,通过这个对象的builder可以调用到全局@Builder函数,如许就可以将全局@Builder函数以包装对象的形式在组件间举行赋值和通报了。
  3.1 接口阐明

wrapBuilder是一个模板函数,返回一个WrappedBuilder对象。
  1. // declare关键字主要用于声明变量、模块、函数或类的类型,不需要立即实现它们
  2. declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;
复制代码
同时WrappedBuilder对象也是一个模板类:
  1. // 模板参数Args extends Object[] 是需要包装的builder函数的参数列表
  2. declare class WrappedBuilder< Args extends Object[]> {
  3.   builder: (...args: Args) => void;
  4.   constructor(builder: (...args: Args) => void);
  5. }
复制代码
使用方法如下:
  1. let builderVar: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder)
  2. let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder)] //可以放入数组
复制代码
需要注意⚠️:


  • wrapBuilder方法只能传入全局@Builder方法;
  • wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct(组件内部)内部使用;
3.2 使用场景1

将wrapBuilder赋值给globalBuilder,且把MyBuilder作为wrapBuilder参数,用来替换MyBuilder不能直接赋值给globalBuilder:
  1. // 这是一个全局的@Builder修饰的函数(自定义构建函数),需要两个参数,类型为string number
  2. @Builder
  3. function MyBuilder(value: string, size: number) {
  4.   Text(value)
  5.     .fontSize(size)
  6. }
  7. // 这里的[string, number]对应上面自定义构建函数的参数类型,是一个数组哦
  8. let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder);
  9. @Entry
  10. @Component
  11. struct Index {
  12.   @State message: string = 'Hello World';
  13.   build() {
  14.     Row() {
  15.       Column() {
  16.         // 这里可以直接调用builder,其实就是调用最上面的那个全局的@Builder自定义构建函数
  17.         globalBuilder.builder(this.message, 50)
  18.       }
  19.       .width('100%')
  20.     }
  21.     .height('100%')
  22.   }
  23. }
复制代码
3.3 使用场景2

自定义组件Index使用ForEach来举行差别@Builder函数的渲染,可以使用builderArr声明的wrapBuilder数组举行差别@Builder函数效果体现,团体代码会更加整洁:
  1. // 全局的自定义构建函数
  2. @Builder
  3. function MyBuilder(value: string, size: number) {
  4.   Text(value)
  5.     .fontSize(size)
  6. }
  7. // 全局的自定义构建函数
  8. @Builder
  9. function YourBuilder(value: string, size: number) {
  10.   Text(value)
  11.     .fontSize(size)
  12.     .fontColor(Color.Pink)
  13. }
  14. // 这里使用一个数组存储这些WrappedBuilder:builderArr,需要全局的自定义构建函数的参数类型是一致的,如果不一致,那就封装成对象吧!
  15. const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)];
  16. @Entry
  17. @Component
  18. struct Index {
  19.   // 组件内的自定义构建函数
  20.   @Builder testBuilder() {
  21.     // 循环渲染,调用item.builder进行渲染,这里会调用到顶部的全局自定义函数
  22.     ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
  23.       item.builder('Hello World', 30)
  24.     }
  25.     )
  26.   }
  27.   build() {
  28.     Row() {
  29.       Column() {
  30.         this.testBuilder()
  31.       }
  32.       .width('100%')
  33.     }
  34.     .height('100%')
  35.   }
  36. }
复制代码
4. @Styles装饰器:定义组件重用样式

如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在举行重复样式设置,虽然可以复制粘贴,但是为了代码简便性和后续方便维护,鸿蒙提供了可以提炼公共样式举行复用的装饰器@Styles。
@Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用,通过@Styles装饰器可以快速定义并复用自定义样式。
   上面是官方的阐明,简朴的来说就是把多个组件通用的属性和方法封装成一个方法,在创建组件的时候可以直接使用,避免重复写样式代码;嗯。。。类似前端CSS中按class分类吧。
  4.1 装饰器使用阐明



  • 当前@Styles仅支持通用属性和通用变乱;
  • @Styles方法不支持参数;
  1. // 错误❌: @Styles不支持参数
  2. @Styles function globalFancy (value: number) {
  3.   .width(value)
  4. }
复制代码


  • @Styles可以定义在组件内或全局,在全局定义时需要在方法名前面添加function关键字,组件内定义时则不需要添加function关键字;
  • 只能在当前文件内使用,不支持export;
  1. // 全局
  2. @Styles function functionName() { ... }
  3. // 在组件内
  4. @Component
  5. struct FancyUse {
  6.   @Styles fancy() {
  7.     .height(100)
  8.   }
  9. }
复制代码


  • 定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过变乱来改变状态变量的值,示例如下:
  1. @Component
  2. struct FancyUse {
  3.   @State heightValue: number = 100
  4.   
  5.   @Styles fancy() {
  6.     .height(this.heightValue)
  7.     .backgroundColor(Color.Yellow)
  8.     .onClick(() => {
  9.       this.heightValue = 200
  10.     })
  11.   }
  12. }
复制代码


  • 组件内@Styles的优先级高于全局的@Styles,框架会优先查找当前组件内的@Styles,如果找不到,就会全局查找;
4.2 使用场景

  1. // 定义在全局的@Styles封装的样式
  2. @Styles function globalFancy  () {
  3.   .width(150)
  4.   .height(100)
  5.   .backgroundColor(Color.Pink)
  6. }
  7. @Entry
  8. @Component
  9. struct FancyUse {
  10.   @State heightValue: number = 100
  11.   
  12.   // 定义在组件内的@Styles封装的样式
  13.   @Styles fancy() {
  14.     .width(200)
  15.     .height(this.heightValue)
  16.     .backgroundColor(Color.Yellow)
  17.     .onClick(() => {
  18.       this.heightValue = 200
  19.     })
  20.   }
  21.   build() {
  22.     Column({ space: 10 }) {
  23.       // 使用全局的@Styles封装的样式
  24.       Text('FancyA')
  25.         .globalFancy()
  26.         .fontSize(30)
  27.       // 使用组件内的@Styles封装的样式
  28.       Text('FancyB')
  29.         .fancy()
  30.         .fontSize(30)
  31.     }
  32.   }
  33. }
复制代码
5. @Extend装饰器:定义扩展组件样式

上面的@Styles用于样式的扩展,在@Styles的底子上,鸿蒙又提供了@Extend,用于扩展原生组件样式。相比于@Styles提供了更多的扩展的能力。
5.1 使用阐明

语法:
  1. @Extend(UIComponentName) function functionName { ... }
复制代码
使用规则:


  • 和@Styles差别,@Extend仅支持在全局定义。并且也只能在当前文件中使用;
  • 和@Styles差别,@Extend支持封装指定的组件的私有属性和私有变乱,以及预定义相同组件的@Extend的方法;
  1. // @Extend(Text)可以支持Text的私有属性fontColor
  2. @Extend(Text) function fancy () {
  3.   .fontColor(Color.Red)
  4. }
  5. // superFancyText可以调用预定义的fancy
  6. @Extend(Text) function superFancyText(size:number) {
  7.     .fontSize(size)
  8.     .fancy()
  9. }
复制代码


  • 和@Styles差别,@Extend装饰的方法支持参数,开发者可以在调用时通报参数,调用依照TS方法传值和调用;
  1. // xxx.ets
  2. @Extend(Text) function fancy (fontSize: number) {
  3.   .fontColor(Color.Red)
  4.   .fontSize(fontSize)
  5. }
  6. @Entry
  7. @Component
  8. struct FancyUse {
  9.   build() {
  10.     Row({ space: 10 }) {
  11.       Text('Fancy')
  12.         .fancy(16)
  13.       Text('Fancy')
  14.         .fancy(24)
  15.     }
  16.   }
  17. }
复制代码


  • @Extend装饰的方法的参数可以为function,作为Event变乱的句柄:
  1. @Extend(Text) function makeMeClick(onClick: () => void) {
  2.   .backgroundColor(Color.Blue)
  3.   .onClick(onClick)
  4. }
  5. @Entry
  6. @Component
  7. struct FancyUse {
  8.   @State label: string = 'Hello World';
  9.   onClickHandler() {
  10.     this.label = 'Hello ArkUI';
  11.   }
  12.   build() {
  13.     Row({ space: 10 }) {
  14.       Text(`${this.label}`)
  15.         .makeMeClick(() => {this.onClickHandler()})
  16.     }
  17.   }
  18. }
复制代码


  • @Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染
  1. @Extend(Text) function fancy (fontSize: number) {
  2.   .fontColor(Color.Red)
  3.   .fontSize(fontSize)
  4. }
  5. @Entry
  6. @Component
  7. struct FancyUse {
  8.   
  9.   @State fontSizeValue: number = 20
  10.   
  11.   build() {
  12.     Row({ space: 10 }) {
  13.       Text('Fancy')
  14.         .fancy(this.fontSizeValue)
  15.         .onClick(() => {
  16.           this.fontSizeValue = 30
  17.         })
  18.     }
  19.   }
  20. }
复制代码
5.2 使用场景

以下示例声明了3个Text组件,每个Text组件均设置了fontStyle、fontWeight和backgroundColor样式:
  1. @Entry
  2. @Component
  3. struct FancyUse {
  4.   @State label: string = 'Hello World'
  5.   build() {
  6.     Row({ space: 10 }) {
  7.       Text(`${this.label}`)
  8.         .fontStyle(FontStyle.Italic)
  9.         .fontWeight(100)
  10.         .backgroundColor(Color.Blue)
  11.       Text(`${this.label}`)
  12.         .fontStyle(FontStyle.Italic)
  13.         .fontWeight(200)
  14.         .backgroundColor(Color.Pink)
  15.       Text(`${this.label}`)
  16.         .fontStyle(FontStyle.Italic)
  17.         .fontWeight(300)
  18.         .backgroundColor(Color.Orange)
  19.     }.margin('20%')
  20.   }
  21. }
复制代码
可以使用@Extend将样式组合复用,示例如下:
  1. // 组合
  2. @Extend(Text) function fancyText(weightValue: number, color: Color) {
  3.   .fontStyle(FontStyle.Italic)
  4.   .fontWeight(weightValue)
  5.   .backgroundColor(color)
  6. }
  7. @Entry
  8. @Component
  9. struct FancyUse {
  10.   @State label: string = 'Hello World'
  11.   build() {
  12.     Row({ space: 10 }) {
  13.       Text(`${this.label}`)
  14.         .fancyText(100, Color.Blue)
  15.       Text(`${this.label}`)
  16.         .fancyText(200, Color.Pink)
  17.       Text(`${this.label}`)
  18.         .fancyText(300, Color.Orange)
  19.     }.margin('20%')
  20.   }
  21. }
复制代码
6. stateStyles:多态样式

@Styles和@Extend仅仅应用于静态页面的样式复用,stateStyles可以依据组件的内部状态的差别,快速设置差别的样式,可以称为多态样式。
   就是类似CSS的伪类,针对于按钮点击、按压、获取焦点等,分别设置差别的样式;
  6.1 概述

stateStyles是属性方法,可以根据UI内部状态来设置样式,类似css伪类,但是语法差别。ArkUI提供以下5种状态:


  • focused
  • normal
  • pressed
  • disabled
  • selected
6.2 底子使用场景

下面的示例展示了stateStyles最根本的使用场景。Button1处于第一个组件,Button2处于第二个组件。按压时显示为pressed态指定的玄色。使用Tab键走焦,先是Button1获焦并显示为focus态指定的粉色。当Button2获焦的时候,Button2显示为focus态指定的粉色,Button1失焦显示normal态指定的红色。
  1. @Entry
  2. @Component
  3. struct StateStylesSample {
  4.   build() {
  5.     Column() {
  6.       Button('Button1')
  7.         .stateStyles({
  8.           focused: {
  9.             .backgroundColor(Color.Pink)
  10.           },
  11.           pressed: {
  12.             .backgroundColor(Color.Black)
  13.           },
  14.           normal: {
  15.             .backgroundColor(Color.Red)
  16.           }
  17.         })
  18.         .margin(20)
  19.       Button('Button2')
  20.         .stateStyles({
  21.           focused: {
  22.             .backgroundColor(Color.Pink)
  23.           },
  24.           pressed: {
  25.             .backgroundColor(Color.Black)
  26.           },
  27.           normal: {
  28.             .backgroundColor(Color.Red)
  29.           }
  30.         })
  31.     }.margin('30%')
  32.   }
  33. }
复制代码
6.3 @Styles和stateStyles联合使用

以下示例通过@Styles指定stateStyles的差别状态:
  1. @Entry
  2. @Component
  3. struct MyComponent {
  4.   @Styles normalStyle() {
  5.     .backgroundColor(Color.Gray)
  6.   }
  7.   @Styles pressedStyle() {
  8.     .backgroundColor(Color.Red)
  9.   }
  10.   build() {
  11.     Column() {
  12.       Text('Text1')
  13.         .fontSize(50)
  14.         .fontColor(Color.White)
  15.         .stateStyles({
  16.           normal: this.normalStyle,
  17.           pressed: this.pressedStyle,
  18.         })
  19.     }
  20.   }
  21. }
复制代码
7. @AnimatableExtend装饰器:定义可动画属性

@AnimatableExtend装饰器用于自定义可动画的属性方法,在这个属性方法中修改组件不可动画的属性。在动画执行过程时,通过逐帧回调函数修改不可动画属性值,让不可动画属性也能实现动画效果。


  • 可动画属性:如果一个属性在animation属性前调用,改变这个属性的值可以见效animation属性的动画效果,这个属性称为可动画属性,比如height、width、backgroundColor、translate属性,Text组件的fontSize属性等;
  • 不可动画属性:如果一个属性方法在animation属性前调用,改变这个属性的值不能见效animation属性的动画效果,这个属性称为不可动画属性,比如Polyline组件的points属性等;
7.1 使用阐明

  1. // 1. @AnimatableExtend仅支持在全局定义;
  2. // 2. 函数参数类型必须为number类型或者实现AnimtableArithmetic<T>接口的自定义类型;
  3. // 3. 函数体内只能调用@AnimatableExtend括号组件的属性方法;
  4. @AnimatableExtend(UIComponentName) function functionName(value: typeName) {
  5.   .propertyName(value)
  6. }
复制代码

7.2 使用场景

实现字体大小的动画效果:
  1. @AnimatableExtend(Text) function animatableFontSize(size: number) {
  2.   .fontSize(size)
  3. }
  4. @Entry
  5. @Component
  6. struct AnimatablePropertyExample {
  7.   @State fontSize: number = 20
  8.   build() {
  9.     Column() {
  10.       Text("AnimatableProperty")
  11.         .animatableFontSize(this.fontSize)
  12.         .animation({duration: 1000, curve: "ease"})
  13.       Button("Play")
  14.         .onClick(() => {
  15.           this.fontSize = this.fontSize == 20 ? 36 : 20
  16.         })
  17.     }.width("100%")
  18.     .padding(10)
  19.   }
  20. }
复制代码
8. @Require装饰器:校验构造传参

@Require装饰器不能单独使用,和@Prop和@BuilderParam配合使用。在构造自定义组件时,用@Require修饰的@Prop和@BuilderParam变量,必须在构造时传参。
   @Require装饰器仅用于装饰struct内的@Prop和@BuilderParam成员状态变量。
  8.1 使用场景

当Child组件内使用@Require装饰器和@Prop或者@BuilderParam结合使用时,父组件Index在构造Child时必须传参,否则编译不通过。
  1. @Entry
  2. @Component
  3. struct Index {
  4.   @State message: string = 'Hello World';
  5.   @Builder buildTest() {
  6.     Row() {
  7.       Text('Hello, world')
  8.         .fontSize(30)
  9.     }
  10.   }
  11.   build() {
  12.     Row() {
  13.       Child({ initMessage: this.message, message: this.message,
  14.         buildTest: this.buildTest, initbuildTest: this.buildTest })
  15.     }
  16.   }
  17. }
  18. @Component
  19. struct Child {
  20.   @Builder buildFuction() {
  21.     Column() {
  22.       Text('initBuilderParam')
  23.         .fontSize(30)
  24.     }
  25.   }
  26.   // 使用@Require标识父组件在构造Child组件时,必须使用构造传参;
  27.   @Require @BuilderParam buildTest: () => void;
  28.   @Require @BuilderParam initbuildTest: () => void = this.buildFuction;
  29.   @Require @Prop initMessage: string = 'Hello';
  30.   @Require @Prop message: string;
  31.   build() {
  32.     Column() {
  33.       Text(this.initMessage)
  34.         .fontSize(30)
  35.       Text(this.message)
  36.         .fontSize(30)
  37.       this.initbuildTest();
  38.       this.buildTest();
  39.     }
  40.     .width('100%')
  41.     .height('100%')
  42.   }
  43. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张裕

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表