本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、ArkUI动画核心概念

1. 动画类型速查表

动画类型 适用场景 性能对比 代码复杂度
属性动画 大小/位置/透明度变化 ★★★★ ★★
显式动画 复杂路径运动 ★★★ ★★★
转场动画 页面/组件切换 ★★★★ ★★
粒子动画(NEXT) 特效场景(如雨雪效果) ★★ ★★★★

2. 动画性能优化三原则

  1. 减少布局重计算:使用width('100%')而非具体像素值
  2. 优先使用硬件加速:添加animation({ timing: 'hardware' })
  3. 避免频繁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像素 硬件纹理尺寸限制
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐