【Day 11】鸿蒙动画开发实战:从基础动效到交互动画
·
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、ArkUI动画核心概念
1. 动画类型速查表
| 动画类型 | 适用场景 | 性能对比 | 代码复杂度 |
|---|---|---|---|
| 属性动画 | 大小/位置/透明度变化 | ★★★★ | ★★ |
| 显式动画 | 复杂路径运动 | ★★★ | ★★★ |
| 转场动画 | 页面/组件切换 | ★★★★ | ★★ |
| 粒子动画(NEXT) | 特效场景(如雨雪效果) | ★★ | ★★★★ |
2. 动画性能优化三原则
- 减少布局重计算:使用
width('100%')而非具体像素值 - 优先使用硬件加速:添加
animation({ timing: 'hardware' }) - 避免频繁GC:复用动画对象而非重复创建
二、基础动画实战
1. 属性动画:按钮放大效果
@Entry
@Component
struct ScaleButton {
@State scaleValue: number = 1
build() {
Button('点击放大')
.scale({ x: this.scaleValue, y: this.scaleValue })
.onClick(() => {
animateTo({ duration: 300 }, () => {
this.scaleValue = 1.5 // 放大到1.5倍
})
})
}
}
关键参数:
duration:动画时长(ms)curve:缓动曲线(默认ease,可选linear/spring等)
2. 转场动画:页面跳转效果
// 页面A跳转时
router.pushUrl({
url: 'pages/PageB',
transition: { type: 'slide', duration: 500 } // 右滑进入
})
// 页面B返回时
router.back({
transition: { type: 'fade', duration: 300 } // 淡出效果
})
三、进阶交互动画
1. 手势驱动动画(拖拽回弹)
@Entry
@Component
struct DragBall {
@State offsetX: number = 0
@State offsetY: number = 0
build() {
Stack() {
Circle({ width: 50, height: 50 })
.position({ x: this.offsetX, y: this.offsetY })
.gesture(
PanGesture({ distance: 5 })
.onActionUpdate((event: GestureEvent) => {
this.offsetX = event.offsetX
this.offsetY = event.offsetY
})
.onActionEnd(() => {
animateTo({ curve: 'spring' }, () => {
this.offsetX = 0 // 自动回弹到原点
this.offsetY = 0
})
})
)
}
}
}
2. 粒子动画实现(NEXT专属)
import { ParticleSystem } from '@ohos.animation'
@Component
struct SnowEffect {
private particleSys = new ParticleSystem(200) // 最大200个粒子
aboutToAppear() {
this.particleSys.setConfig({
emitterX: 0,
emitterY: -100,
speed: 0.2,
lifespan: 3000,
texture: $r('app.media.snowflake')
})
}
build() {
Canvas(this.particleSys.getController()) // 绑定画布
}
}
四、实战:购物车动画
1. 商品飞入效果
@Entry
@Component
struct AddToCart {
@State cartPos: { x: number, y: number } = { x: 0, y: 0 }
@State @Watch('onBallMove') ballPos: { x: number, y: number } = { x: 0, y: 0 }
onBallMove() {
if (this.ballPos.y > 100) {
animateTo({ duration: 200 }, () => {
this.cartPos = { x: this.ballPos.x, y: this.ballPos.y }
})
}
}
build() {
Column() {
Button('加入购物车')
.onClick(() => {
this.ballPos = { x: 150, y: 300 } // 触发动画
})
Image($r('app.media.cart'))
.position({ x: this.cartPos.x, y: this.cartPos.y })
}
}
}
五、避坑指南
| 常见问题 | 解决方案 | 原理说明 |
|---|---|---|
| 动画卡顿 | 检查是否在主线程执行耗时操作 | UI线程阻塞导致丢帧 |
| 转场动画失效 | 确认页面栈未超过32层 | 系统安全限制 |
| 粒子动画不显示 | 检查纹理资源是否超过1024x1024像素 | 硬件纹理尺寸限制 |
更多推荐


所有评论(0)