鸿蒙开发笔记-5-装饰器之@Styles装饰器,@Extend装饰器,stateStyles多态样式,@AnimatableExtend装饰器

95 阅读3分钟

一、@Styles装饰器:组件级样式复用

1. 核心特性

@Styles装饰器是ArkUI框架中实现样式复用的基础工具,支持组件内定义全局定义两种模式。组件内定义的@Styles方法可以访问组件的状态变量(如@State),而全局定义需添加function关键字且不支持状态绑定。其优先级遵循组件内样式 > 全局样式 > 原生默认样式

2. 应用场景

// 全局样式(不支持状态访问)
@Styles function globalStyle() {
  .width(150)
  .height(100)
  .backgroundColor(Color.Pink)
}

@Component struct CustomComponent {
  @State private btnHeight: number = 50
  
  // 组件内动态样式
  @Styles btnStyle() {
    .height(this.btnHeight)
    .backgroundColor('#FF4081')
    .onClick(() => this.btnHeight = 80)
  }

  build() {
    Column() {
      Button('全局样式').globalStyle()
      Button('动态样式').btnStyle()
    }
  }
}

限制:仅支持通用属性/事件,不支持参数传递。


二、@Extend装饰器:组件能力扩展

1. 核心优势

@Extend装饰器通过参数化配置私有属性支持实现组件扩展。其特点包括:

  • 支持目标组件的私有属性(如Text的fontColor
  • 允许传递函数参数实现事件绑定
  • 支持链式调用组合多个扩展方法。

2. 典型应用

// 扩展Text组件样式
@Extend(Text) 
function highlightText(size: number, color: Color) {
  .fontSize(size)
  .fontColor(color)
  .textShadow({ radius: 2, color: Color.Black })
}

// 带事件处理的扩展
@Extend(Button) 
function animatedButton(onClick: () => void) {
  .scale({ x: 0.95, y: 0.95 })
  .onClick(onClick)
}

// 使用示例
Text('重要提示').highlightText(24, Color.Red)
Button('提交').animatedButton(() => submitForm())

三、stateStyles:动态状态响应

1. 状态类型体系

状态类型触发条件典型组件
normal默认状态所有组件
pressed按压状态(触摸/鼠标按下)Button
focused获焦状态(Tab键导航)TextInput
disabled禁用状态Switch/Button
selected选中状态TabBar/Checkbox

2. 实现方案

@Component struct StatefulComponent {
  @Styles pressedStyle() {
    .backgroundColor('#FF5252')
    .scale({ x: 0.95, y: 0.95 })
  }

  build() {
    Button('动态按钮')
      .stateStyles({
        normal: { 
          .backgroundColor('#2196F3') 
        },
        pressed: this.pressedStyle,
        disabled: {
          .opacity(0.5)
          .backgroundColor('#BDBDBD')
        }
      })
  }
}

进阶技巧:与@State变量联动实现动态样式切换。


四、@AnimatableExtend:动画属性扩展

1. 实现原理

通过实现AnimatableArithmetic接口定义数值运算规则,使不可动画属性(如Polyline的points)支持动画效果。

2. 开发实践

// 自定义动画向量类型
class Vector2D implements AnimatableArithmetic<Vector2D> {
  x: number = 0
  y: number = 0
  
  plus(rhs: Vector2D): Vector2D {
    return new Vector2D(this.x + rhs.x, this.y + rhs.y)
  }
  // 实现其他运算符...
}

// 扩展Polyline组件
@AnimatableExtend(Polyline) 
function animPath(points: Vector2D[]) {
  .points(points.map(p => [p.x, p.y]))
}

@Component struct PathAnimation {
  @State path: Vector2D[] = [new Vector2D(0,0), new Vector2D(100,100)]
  
  build() {
    Polyline()
      .animPath(this.path)
      .animation({ duration: 2000, curve: Curve.EaseInOut })
      .onClick(() => {
        this.path = [new Vector2D(200,50), new Vector2D(300,200)]
      })
  }
}

适用场景:路径动画、颜色渐变、自定义布局动画。


五、对比

特性@Styles@ExtendstateStyles@AnimatableExtend
核心目的样式复用组件扩展状态响应动画扩展
定义位置组件/全局全局组件内全局
参数支持
状态感知组件内样式支持
动画支持
私有属性访问

六、总结

  • 基础样式(@Styles) :定义全局基础样式(如按钮尺寸、字体规范)
  • 组件扩展(@Extend) :创建组件变体(如带图标的按钮)
  • 状态样式(stateStyles) :处理交互状态(按压/禁用样式)
  • 动画扩展(@AnimatableExtend):实现复杂动效

性能优化建议

  • 避免在@Styles中进行复杂计算
  • stateStyles建议使用纯数值状态变量
  • 优先使用系统内置动画属性,必要时再使用自定义动画

综合示例

// 样式分层架构
@Styles function baseButton() { 
  .padding(10).borderRadius(5) 
}

@Extend(Button)
function primaryButton() {
  baseButton()
  .backgroundColor(BrandColor.Primary)
  .stateStyles({
    pressed: {
      .opacity(0.8)
    }
  })
}

// 实现动画按钮
@AnimatableExtend(Button)
function scaleButton(scale: number) {
  .scale({ x: scale, y: scale })
}

@Entry
@Component struct SmartButtonPage {
  @State btnScale: number = 1

  build() {
    Column() {
      Button('智能按钮')
        .primaryBtn()
        .scaleButton(this.btnScale)
        .animation({ curve: Curve.Spring })
        .onClick(() => {
          this.btnScale = this.btnScale > 1 ? 1 : 1.2
        })
    }
  }
}

我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章