ArkUI @AnimatableExtend:样式能动,过渡才不生硬
ArkUI @AnimatableExtend:样式能动,过渡才不生硬
今天我们给 Text 扩展一个会参与动画的宽度属性,让一条蓝色进度块在按钮点击后平滑展开和收回。
普通 @Extend 更像是把一组样式收起来。@AnimatableExtend 多了一层意思:这个扩展属性的参数会参与动画过程,ArkUI 会在动画中逐帧把中间值传进去。
参考文档:组件扩展
先说边界
@AnimatableExtend 很有用,但别一上来就写很复杂。
- 它必须定义在全局,不能写在组件内部。
- 函数体里只能调用括号里指定组件的属性方法。
- 参数可以是
number,也可以是实现AnimatableArithmetic的自定义类型。
这篇我们只用 number。自定义类型能做更复杂的动画,但新手第一步没必要把门槛抬那么高。
定义一个可动画扩展属性
我们先给 Text 扩展一个宽度方法:
@AnimatableExtend(Text)
function animatableBarWidth(widthValue: number) {
.width(widthValue)
}
这段代码只做一件事:把传进来的数字用到 Text.width() 上。
容易写错的地方也在这里:函数体里不要顺手写别的组件,也不要在组件内部声明这个函数。
用状态驱动宽度变化
页面里保留一个宽度值:
@State barWidth: number = 120;
点击按钮时,在两个宽度之间切换:
this.barWidth = this.expanded ? 260 : 120;
如果只是这么写,宽度会变,但变化可能比较硬。我们给组件挂上动画:
Text(' ')
.height(44)
.animatableBarWidth(this.barWidth)
.animation({ duration: 500, curve: Curve.EaseInOut })
这样 barWidth 从 120 变到 260 时,中间过程就会被动画接住。
这个 Demo 看什么
页面上只有一个蓝色条块、一个当前宽度数字和一个按钮。
点击“展开宽度”,条块会平滑变长;再点“收回宽度”,它会缩回去。我们刻意没有加更多视觉效果,因为这篇想让你盯住一个重点:自定义扩展属性也可以参与动画。
如果你项目里有一些“明明只是样式变化,却看起来很生硬”的地方,可以先想想它是不是适合拆成一个可动画扩展属性。
完整示例代码
文件位置:entry/src/main/ets/pages/arkUI/custom/ArkUIAnimatableExtendDemo.ets
@AnimatableExtend(Text)
function animatableBarWidth(widthValue: number) {
.width(widthValue)
}
@Entry
@Component
struct ArkUIAnimatableExtendDemo {
@State barWidth: number = 120;
@State expanded: boolean = false;
@Builder
HeaderBlock() {
Column({ space: 8 }) {
Text('ArkUI @AnimatableExtend')
.fontSize(28)
.fontWeight(700)
.fontColor('#111827')
Text('样式能动,过渡才不生硬')
.fontSize(16)
.fontColor('#4B5563')
Text('@AnimatableExtend 可以把自定义扩展属性接入动画过程。本篇先用 number 参数做最小示例。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
private toggleWidth(): void {
this.expanded = !this.expanded;
this.barWidth = this.expanded ? 260 : 120;
}
build() {
Scroll() {
Column({ space: 20 }) {
this.HeaderBlock()
Column({ space: 14 }) {
Text('宽度跟着数字参数动')
.fontSize(18)
.fontWeight(700)
.fontColor('#111827')
Text(' ')
.height(44)
.animatableBarWidth(this.barWidth)
.borderRadius(22)
.backgroundColor('#2563EB')
.animation({ duration: 500, curve: Curve.EaseInOut })
Text(`当前宽度:${this.barWidth}`)
.fontSize(14)
.fontColor('#4B5563')
}
.width('100%')
.padding(16)
.borderRadius(18)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#E5E7EB' })
.alignItems(HorizontalAlign.Start)
Button(this.expanded ? '收回宽度' : '展开宽度')
.height(44)
.borderRadius(22)
.fontSize(15)
.fontWeight(700)
.fontColor('#FFFFFF')
.backgroundColor('#DC2626')
.onClick(() => {
this.toggleWidth();
})
Text('@AnimatableExtend 必须全局定义,函数体里只能调用括号里那个组件的属性方法。参数可以是 number,也可以是实现 AnimatableArithmetic 的自定义类型;这篇先不展开后者。')
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor('#FEF2F2')
.fontSize(14)
.fontColor('#4B5563')
.lineHeight(22)
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#F8FAFC')
}
}
- 点赞
- 收藏
- 关注作者
评论(0)