ArkUI animateTo:让变化有起点,也有落点
【摘要】 今天我们要用 animateTo 做一次显式动画:按钮点击以后,我们把状态修改包起来,让位移、缩放和进度变化一起动。 准备 页面文件是 entry/src/main/ets/pages/arkUI/motion/ArkUIAnimateToDemo.ets。 这一页会故意放一个“直接改状态”的例子。它不是错,只是变化太
ArkUI animateTo:让变化有起点,也有落点
今天我们要用 animateTo 做一次显式动画:按钮点击以后,我们把状态修改包起来,让位移、缩放和进度变化一起动。
准备
页面文件是 entry/src/main/ets/pages/arkUI/motion/ArkUIAnimateToDemo.ets。
这一页会故意放一个“直接改状态”的例子。它不是错,只是变化太硬,方便我们看出 animateTo 的差别。
第一步:直接改状态
this.directMoved = !this.directMoved;
直接改状态时,UI 会马上进入新结果。对于普通开关,这样完全够用。但如果元素位置明显变化,用户就容易觉得页面闪了一下。
第二步:用 animateTo 包住状态修改
this.getUIContext().animateTo({ duration: 520, curve: Curve.EaseInOut }, () => {
this.animatedMoved = !this.animatedMoved;
this.animatedProgress = this.animatedMoved ? 86 : 36;
})
animateTo 的好处是入口清楚:这次点击会带来哪些状态变化,都集中放在回调里。一般来说,一个按钮同时驱动多个位置变化时,用它更好读。
运行后看什么
先点“直接改状态”,你会看到标签直接换位置。再点“用 animateTo 改状态”,标签和进度条会一起过渡。
下一次你遇到“点一下以后多个模块都要动”的场景,可以试着先用 animateTo 收住,不要每个模块各写一段零散动画。
完整示例代码
@Entry
@Component
struct ArkUIAnimateToDemo {
@State directMoved: boolean = false;
@State animatedMoved: boolean = false;
@State animatedProgress: number = 36;
private runAnimatedChange(): void {
this.getUIContext().animateTo({ duration: 520, curve: Curve.EaseInOut }, () => {
this.animatedMoved = !this.animatedMoved;
this.animatedProgress = this.animatedMoved ? 86 : 36;
})
}
@Builder
sectionTitle(title: string, desc: string) {
Column({ space: 6 }) {
Text(title)
.fontSize(19)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text(desc)
.fontSize(13)
.fontColor('#6B7280')
.lineHeight(20)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
build() {
Scroll() {
Column({ space: 22 }) {
Column({ space: 8 }) {
Text('ArkUI animateTo')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text('让变化有起点,也有落点')
.fontSize(16)
.fontColor('#4B5563')
Text('这一页对比两种写法:直接改状态会立刻跳到结果,用 animateTo 包住状态修改,变化会被组织成一段动画。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
this.sectionTitle('直接改状态:结果对,但变化太硬', '不是不能用,只是用户看不到过程。适合不需要动效的开关,不适合明显位置变化。')
Column({ space: 12 }) {
Row() {
Text('直接移动')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.padding({ left: 16, right: 16, top: 10, bottom: 10 })
.borderRadius(18)
.backgroundColor('#64748B')
.translate({ x: this.directMoved ? 128 : 0 })
}
.width('100%')
.height(68)
.padding(12)
.borderRadius(16)
.backgroundColor('#F1F5F9')
Button('直接改状态')
.height(38)
.fontSize(14)
.fontColor('#FFFFFF')
.backgroundColor('#64748B')
.borderRadius(19)
.padding({ left: 18, right: 18 })
.onClick(() => {
this.directMoved = !this.directMoved;
})
}
.width('100%')
.alignItems(HorizontalAlign.Start)
this.sectionTitle('animateTo:把状态变化包成一段动作', '显式动画适合一次按钮点击带动多处变化,逻辑入口更清楚。')
Column({ space: 14 }) {
Row() {
Text('显式动画')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
.padding({ left: 16, right: 16, top: 10, bottom: 10 })
.borderRadius(18)
.backgroundColor('#2563EB')
.translate({ x: this.animatedMoved ? 128 : 0 })
.scale({ x: this.animatedMoved ? 1.12 : 1, y: this.animatedMoved ? 1.12 : 1 })
}
.width('100%')
.height(72)
.padding(12)
.borderRadius(16)
.backgroundColor('#EFF6FF')
Column({ space: 6 }) {
Row() {
Text('进度')
.fontSize(13)
.fontColor('#475569')
Blank()
Text(this.animatedProgress.toString() + '%')
.fontSize(13)
.fontWeight(FontWeight.Bold)
.fontColor('#2563EB')
}
.width('100%')
Row()
.width(this.animatedProgress.toString() + '%')
.height(8)
.borderRadius(4)
.backgroundColor('#2563EB')
}
.width('100%')
.padding(12)
.borderRadius(14)
.backgroundColor('#F8FAFC')
Button('用 animateTo 改状态')
.height(38)
.fontSize(14)
.fontColor('#FFFFFF')
.backgroundColor('#2563EB')
.borderRadius(19)
.padding({ left: 18, right: 18 })
.onClick(() => {
this.runAnimatedChange();
})
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)