ArkUI 动画概述:页面会动之前,先分清谁在动
【摘要】 今天我们先不急着堆动效,而是把 ArkUI 里常见的动画类型摆在一起看清楚。 动画最容易写乱的地方,不是 API 多,而是还没想清楚“到底是谁在动”:是一个属性在变,还是组件在出现消失,还是页面在切换,或者只是想做一点氛围。这个 Demo 就是一个选型页,帮我们先把边界分开。 这个 Demo 看什么 准备一个 Anim
ArkUI 动画概述:页面会动之前,先分清谁在动
今天我们先不急着堆动效,而是把 ArkUI 里常见的动画类型摆在一起看清楚。
动画最容易写乱的地方,不是 API 多,而是还没想清楚“到底是谁在动”:是一个属性在变,还是组件在出现消失,还是页面在切换,或者只是想做一点氛围。这个 Demo 就是一个选型页,帮我们先把边界分开。
这个 Demo 看什么
准备一个 AnimationOverviewItem 类,把动画类型、适用场景、使用提醒和颜色收在一起。页面里用 ForEach 渲染成卡片,这样读起来像一张小抄。
这里没有复杂交互,因为总览页的重点不是“马上动起来”,而是先知道该用哪类能力:
- 属性动画:状态变化后,让尺寸、位置、透明度顺滑过渡。
- 显式动画:用
animateTo明确包住一次状态修改。 - 转场动画:处理组件出现、消失和页面切换。
- 粒子动画:用轻量点位做氛围。
- 帧动画:播放提前准备好的一组图片帧。
你后面写动画时,可以先问自己一句:我现在要解决的是属性变化、组件进出、页面切换,还是视觉氛围?这个问题一清楚,API 选择就不会乱。
下一篇想继续看哪个方向?是更偏“页面手感”的曲线,还是更偏“视觉氛围”的粒子?你可以按自己的项目场景挑一个。
完整代码
class AnimationOverviewItem {
title: string;
scene: string;
note: string;
color: string;
constructor(title: string, scene: string, note: string, color: string) {
this.title = title;
this.scene = scene;
this.note = note;
this.color = color;
}
}
@Entry
@Component
struct ArkUIAnimationOverviewDemo {
private items: AnimationOverviewItem[] = [
new AnimationOverviewItem('属性动画', '状态改变后,让尺寸、位置、透明度这些属性顺滑过渡。', '适合卡片展开、按钮强调、模块轻微位移。', '#2563EB'),
new AnimationOverviewItem('显式动画', '把一次状态修改放进 animateTo 里,明确这次变化怎么动。', '适合点击后的一段明确反馈。', '#0F766E'),
new AnimationOverviewItem('转场动画', '组件出现、消失,或者页面切换时,不要突然闪出来。', '适合列表项插入、浮层露出、页面进出。', '#B45309'),
new AnimationOverviewItem('粒子动画', '用很多轻量点位制造氛围,不靠一张大图硬撑。', '适合庆祝、提示、背景点缀。', '#9333EA'),
new AnimationOverviewItem('帧动画', '准备多帧图片,一帧一帧播放。', '适合小插画、表情、明确的连续动作。', '#DC2626')
];
@Builder
HeaderBlock() {
Column({ space: 8 }) {
Text('ArkUI 动画概述')
.fontSize(28)
.fontWeight(700)
.fontColor('#111827')
Text('页面会动之前,先分清谁在动')
.fontSize(16)
.fontColor('#4B5563')
Text('这一页不急着写复杂效果,我们先把常见动画放在一张图里看清楚:属性在动、组件在进出、页面在切换,还是用粒子和帧图做氛围。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
@Builder
OverviewCard(item: AnimationOverviewItem) {
Row({ space: 14 }) {
Text('')
.width(6)
.height(72)
.borderRadius(3)
.backgroundColor(item.color)
Column({ space: 8 }) {
Text(item.title)
.fontSize(18)
.fontWeight(700)
.fontColor('#111827')
Text(item.scene)
.fontSize(14)
.fontColor('#374151')
.lineHeight(21)
Text(item.note)
.fontSize(12)
.fontColor('#6B7280')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#E5E7EB' })
}
build() {
Scroll() {
Column({ space: 20 }) {
this.HeaderBlock()
Column({ space: 12 }) {
ForEach(this.items, (item: AnimationOverviewItem) => {
this.OverviewCard(item)
}, (item: AnimationOverviewItem) => item.title)
}
.width('100%')
Column({ space: 8 }) {
Text('我们先这样选')
.fontSize(18)
.fontWeight(700)
.fontColor('#111827')
Text('只是属性变化,先用 animation 或 animateTo;需要出现和消失,再看 transition;想做氛围点缀再用 Particle;已经有连续图片素材,才考虑 ImageAnimator。')
.fontSize(14)
.fontColor('#4B5563')
.lineHeight(22)
}
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor('#F8FAFC')
.border({ width: 1, color: '#E5E7EB' })
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)