一、理解 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.Bluebuild() { 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 版本选择合适的特性。