HarmonyOS之多态样式stateStyles的使用

一、理解 stateStyles 与组件状态

  • 在 HarmonyOS 应用开发中,stateStyles 多态样式可以依据组件的内部状态(如按下、获焦、禁用等)快速设置不同样式,类似于 CSS 伪类的功能,能有效提升应用的交互体验。
  • stateStyles 允许根据组件的不同状态定义样式,无需手动处理状态逻辑。目前支持以下五种状态:
状态 说明
normal 组件正常未交互时的状态
pressed 组件被按下或按压时的状态
focused 组件获得焦点时的状态(如通过 Tab 键导航)
disabled 组件被禁用时的状态(需设置 .enabled(false))
selected 组件被选中时的状态(适用于 Checkbox、Radio 等可选组件,从 API 10 开始支持)

二、如何使用 stateStyles ?

① 基础用法

  • 最直接的方式是在组件的 .stateStyles() 方法中定义不同状态的样式:

    Button('点我点我')
    .margin(20)
    .stateStyles({
    normal: {
    .backgroundColor(Color.Red) // 正常状态为红色
    },
    focused: {
    .backgroundColor(Color.Pink) // 获焦状态为粉色
    },
    pressed: {
    .backgroundColor(Color.Black) // 按压状态为黑色
    },
    disabled: {
    .backgroundColor(Color.Gray) // 禁用状态为灰色
    }
    })

  • 如果组件可能获焦(如页面首个 Button),需注意 focused 样式的影响,可使用 .focusable(false) 禁用焦点,或调整组件顺序。

② 与 @Styles 装饰器联合使用

  • 当样式逻辑复杂或需要复用时,可以先用 @Styles 定义样式,再在 stateStyles 中引用:

    @Styles normalStyle() {
    .backgroundColor(Color.Gray)
    .width(100)
    .height(50)
    }

    复制代码
    @Styles pressedStyle() {
      .backgroundColor(Color.Red)
      .width(200)
      .height(100)
    }
    
    build() {
      Column() {
        Button('点击')
          .stateStyles({
            normal: this.normalStyle,
            pressed: this.pressedStyle,
          })
      }
    }

③ 在 stateStyles 中使用变量

  • stateStyles 可以通过 this 绑定组件内的常规变量和状态变量,实现样式的动态响应,按钮初始获焦时为红色,点击后变为粉色:

    @State focusedColor: Color = Color.Red; // 状态变量
    @State normalColor: Color = Color.Green // 常规变量

    复制代码
    build() {
      Column() {
        Button('clickMe')
          .height(100)
          .width(100)
          .stateStyles({
            normal: {
              .backgroundColor(this.normalColor) // 绑定常规变量
            },
            focused: {
              .backgroundColor(this.focusedColor) // 绑定状态变量
            }
          })
          .onClick(() => {
            this.focusedColor = Color.Pink // 点击事件改变状态变量
          })
          .margin('30%')
      }
    }

④ 处理 selected 选中状态

  • selected 状态常用于可选组件,使用时需要操作组件的选中属性:

    @State isSelected: boolean = false // 控制选中状态

    复制代码
    build() {
      Column() {
        Radio({ value: 'radio1' })
          .checked(this.isSelected) // 绑定选中状态
          .stateStyles({
            normal: {
              .backgroundColor(Color.Black)
            },
            selected: {
              .backgroundColor(Color.Red) // 选中后的样式
            },
          })
          .onClick(() => {
            this.isSelected = !this.isSelected // 点击切换选中状态
          })
      }
    }
  • 支持 selected 状态的组件及其对应属性如下:

组件 支持的参数/属性
Checkbox select
CheckboxGroup selectAll
Radio checked
Toggle isOn
ListItem selected
GridItem selected
MenuItem selected

三、实际应用示例

  • 假如现在有这样一个案例,说的是有一条条目,默认无操作状态下是一个背景颜色,手指点击后改变为另一个背景颜色,当手指松开后又还原为默认的背景颜色,我们该如何实现呢?

  • 首先我们可能会想到:利用 onTouch 事件就可以轻松搞定,手指按下就改变背景,手指抬起就还原背景,如下所示:

    复制代码
    @State message : string = 'Hello World';
    @State itemBgColor : Color = Color.Blue
    
    build() {
    
      Column() {
        Text(this.message)
        .fontColor(Color.White)
      }
      .width('100%')
      .height(100)
      .borderRadius(10)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(this.itemBgColor)
      .onTouch( (event) => {
        if (event.type == TouchType.Down) {
          this.itemBgColor = Color.Orange
        } else if (event.type == TouchType.Up) {
          this.itemBgColor = Color.Blue
        }
      })

    }

  • 在实际的开发中可能会有很多个属性的改变,比如宽高,边距等等,那么就需要很多个属性进行赋值,此种写法上,除了实现 onTouch 方法,还需要定义可变化的变量才能切换状态,代码上显得稍显冗余,有没有一种简洁的方式,直接更改属性呢?当然是有的,这就是 stateStyles,把以上的代码,使用 stateStyles 来实现一下,代码如下:

    @State message : string = 'Hello World';
    @State itemBgColor : Color = Color.Blue

    复制代码
    build() {
    
      Column() {
        Text(this.message)
        .fontColor(Color.White)
      }
      .width('100%')
      .height(100)
      .borderRadius(10)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(this.itemBgColor)
      .stateStyles({        
      	pressed: { // 按压          
      		.backgroundColor(Color.Orange)        
      	},        
      	normal: { // 正常态          
      	.backgroundColor(Color.Blue)        
      	}
      })

    }

  • 以上的代码运行之后,可以发现效果和上边的 onTouch 是一模一样的。stateStyles 是支持组件自身的所有属性的,比如再增加一下其他的属性:

    .stateStyles({
    pressed: { // 按压
    .backgroundColor(Color.Orange)
    .width("100%")
    },
    normal: { // 正常态
    .backgroundColor(Color.Blue)
    .width("80%")
    }
    })

  • 如果修改的样式比较多,stateStyles 可以结合 @Styles 装饰器一起来使用,如如上面的案例,可以做如下修改:

    @Styles normalStyle() {
    .backgroundColor(Color.Blue)
    .width("80%")
    }
    @Styles pressedStyle() {
    .backgroundColor(Color.Orange)
    .width("100%")
    }

    .stateStyles({
    pressed: this.pressedStyle,
    normal: this.normalStyle
    })

  • disabled 状态,只有设置了组件禁用参会进行展示,比如下面的案例,设置了组件禁用:

    .enabled(false)
    .stateStyles({
    disabled: {
    .backgroundColor(Color.Blue)
    }
    })

  • 除了以上的三种状态外,再看看一个状态 selected,它一般适用于可选择的组件,比如 Checkbox,Radio 等,如下示例:

    Radio({ value: 'radio', group: 'radioGroup' })
    .checked(this.isChecked)
    .height(50)
    .width(50)
    .borderWidth(0)
    .borderRadius(30)
    .onClick(() => {
    this.isChecked = !this.isChecked
    })
    .radioStyle({ checkedBackgroundColor: Color.Pink })
    .stateStyles({
    normal: {
    .backgroundColor(Color.Blue)
    },
    selected: {
    .backgroundColor(Color.Orange)
    }
    })

  • 在使用多态样式 stateStyles 的时候,需要注意一点,那就是当 clicked 和 pressed 同时在一个组件上使用时,只有后注册的状态才能生效。

  • 最后附录一个具有多种状态的交互式按钮:

    @State isEnable: boolean = true

    复制代码
    // 定义不同状态的样式
    @Styles normalStyle() {
      .backgroundColor("#00BFFF")
      .borderRadius(12)
      .width(110)
      .height(30)
    }
    
    @Styles pressedStyle() {
      .backgroundColor("#FF8C00")
      .borderRadius(15)
      .width(130)
      .height(35)
    }
    
    @Styles disabledStyle() {
      .backgroundColor("#D3D3D3")
      .borderRadius(12)
      .width(100)
      .height(30)
    }
    
    build() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
        Button(this.isEnable ? "有效按钮" : "禁用按钮")
          .fontSize(16)
          .fontColor(Color.White)
          .enabled(this.isEnable) // 控制按钮是否可用
          .stateStyles({
            normal: this.normalStyle,
            pressed: this.pressedStyle,
            disabled: this.disabledStyle,
          })
          .onClick(() => {
            // 点击事件
            console.log("按钮被点击")
          })
    
        Button("控制状态")
          .onClick(() => {
            this.isEnable = !this.isEnable // 切换按钮的可用状态
          })
      }
      .width(400)
      .height(350)
    }

四、注意点

  • 通用属性限制:stateStyles 多态样式只支持通用属性。尝试设置组件私有属性(如 Text 的 fontColor)是无效的。如果遇到此类需求,可以考虑使用 attributeModifier 动态设置属性。
  • @Styles 的限制:与 stateStyles 类似,@Styles 装饰器也仅支持通用属性和通用事件,并且方法内部不能有参数。若在 @Styles 中使用了非通用属性,编译时会报错 .stateStyles doesn't conform standard(API 9)。
  • API 版本兼容:请注意不同状态的 API 支持版本,特别是 selected 状态从 API Version 10 才开始支持。开发时请根据项目的目标 API 版本选择合适的特性。
相关推荐
GLAB-Mary8 小时前
HCIE最优规划路线:如何系统性学习华为认证?
学习·华为·华为认证·hcie·数通
lqj_本人8 小时前
鸿蒙Cordova插件架构与OnsenUI组件适配机制深度解析
华为·架构·harmonyos
猫林老师12 小时前
Flutter for HarmonyOS开发指南(六):测试、调试与质量保障体系
flutter·华为·harmonyos
小Mei数码说16 小时前
华为WATCH 5:连接心与心,让生活更美好
华为·智能手表
爱笑的眼睛1116 小时前
HarmonyOS 应用开发中的内存泄漏检测与修复:深入探索与实践指南
华为·harmonyos
kangyouwei17 小时前
鸿蒙开发:19-本地开发配置bash环境执行hvigorw命令
前端·harmonyos
爱笑的眼睛1117 小时前
HarmonyOS 应用开发:系统权限申请与管理深度解析
华为·harmonyos
DIY机器人工房19 小时前
科普:华为星闪是什么?华为星闪(英文名 NearLink)是国际星闪无线短距通信联盟发布的新型无线短距通信标准技术。
stm32·嵌入式硬件·华为·嵌入式·diy机器人工房·嵌入式面试题
天黑请闭眼20 小时前
华为对象存储:nginx代理临时访问地址后访问报错:Authentication Failed
nginx·华为