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

一、属性动画概述

属性动画是ArkUI框架中通过可动画属性改变引起UI上产生连续视觉效果的基础动画机制。当组件的某些属性值发生变化时,系统会自动在这些值之间进行平滑过渡,从而创建出流畅的动画效果。

核心特点

  • 连续性:在属性值之间创建平滑过渡
  • 可定制性:支持自定义动画参数(时长、曲线、延迟等)
  • 多属性支持:可同时为多个属性添加动画效果
  • 状态驱动:基于状态变量的变化驱动动画

二、ArkUI动画接口对比

ArkUI提供三种主要的属性动画接口,各有不同的适用场景:

动画接口 作用域 原理 使用场景
animateTo 闭包内属性变化 对闭包前后界面差异做动画 多属性相同参数动画、嵌套动画
animation 组件属性变化 自动检测属性变化并添加动画 多属性不同参数动画
keyframeAnimateTo 多个闭包分段变化 分段属性动画 同一属性连续多个动画

三、animateTo动画实现

基本原理

animateTo通过对闭包执行前后UI状态的差异比较,自动为发生变化的可动画属性添加动画效果。

代码示例

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct AnimationExample {
  @State isAnimating: boolean = false;
  @State rotationAngle: number = 0;
  @State moveDistance: number = 0;
  @State transparency: number = 1;

  build() {
    Column() {
      // 可动画组件1 - 旋转方块
      Column() {
        Text('旋转元素')
          .fontColor(Color.White)
      }
      .width(120)
      .height(120)
      .backgroundColor('#317AF7')
      .borderRadius(16)
      .rotate({ angle: this.rotationAngle }) // 绑定旋转角度
      .onClick(() => {
        // 获取UI上下文并执行动画
        this.getUIContext()?.animateTo({
          duration: 800, // 动画时长
          curve: curves.springMotion() // 弹簧曲线
        }, () => {
          this.isAnimating = !this.isAnimating;
          // 在闭包内修改状态变量
          this.rotationAngle = this.isAnimating ? 180 : 0;
          this.moveDistance = this.isAnimating ? 100 : 0;
          this.transparency = this.isAnimating ? 0.6 : 1;
        })
      })

      // 可动画组件2 - 移动并变透明的元素
      Column() {
        Text('移动元素')
          .fontColor(Color.White)
      }
      .width(120)
      .height(120)
      .backgroundColor('#D94838')
      .borderRadius(16)
      .opacity(this.transparency) // 透明度变化
      .translate({ x: this.moveDistance }) // 平移变化
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

关键技术点

  1. 状态变量声明:使用@State装饰器声明需要动画的属性值
  2. 属性绑定:将状态变量绑定到组件的可动画属性
  3. 动画闭包:在animateTo闭包内修改状态变量值
  4. 动画参数配置:通过AnimateParam对象配置动画特性

适用场景

  • 需要同时为多个属性添加相同参数的动画
  • 需要嵌套使用动画的场景
  • 基于用户交互触发的复杂动画序列

四、animation动画实现

基本原理

animation接口通过直接绑定到组件属性,自动检测属性变化并添加动画效果,无需使用闭包。

代码示例

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct AutoAnimationExample {
  @State isActive: boolean = false;
  @State scaleLevel: number = 1;
  @State backgroundColor: Color = Color.Blue;

  build() {
    Column() {
      Button('触发动画')
        .onClick(() => {
          this.isActive = !this.isActive;
          this.scaleLevel = this.isActive ? 1.5 : 1;
          this.backgroundColor = this.isActive ? Color.Red : Color.Blue;
        })
        .width(150)
        .height(60)
        .backgroundColor(this.backgroundColor)
        .scale({ x: this.scaleLevel, y: this.scaleLevel })
        .animation({
          duration: 500,
          curve: curves.easeInOut,
          delay: 100 // 动画延迟
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

技术特点

  1. 自动检测:自动识别属性变化并添加动画
  2. 独立配置:可为不同属性配置不同的动画参数
  3. 执行顺序animation只对其上方的属性调用生效
  4. 链式调用:支持多个属性的链式动画配置

配置示例

Column()
  .width(this.currentWidth)
  .animation({ duration: 300, curve: curves.easeIn }) // 仅对width生效
  
  .height(this.currentHeight) 
  .animation({ duration: 500, curve: curves.spring }) // 对width和height都生效
  
  .backgroundColor(this.currentColor)
  // 没有animation,不产生动画

五、keyframeAnimateTo动画实现

基本原理

keyframeAnimateTo支持创建分段的关键帧动画,适合需要精细控制动画过程的场景。

代码示例

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct KeyframeAnimationExample {
  @State currentPosition: number = 0;
  
  build() {
    Column() {
      Button('执行关键帧动画')
        .onClick(() => {
          this.getUIContext()?.keyframeAnimateTo({
            duration: 1000,
            curve: curves.linear
          }, () => {
            // 第一段动画:向右移动
            this.currentPosition = 200;
          }, () => {
            // 第二段动画:向下移动
            this.currentPosition = 200;
          }, () => {
            // 第三段动画:返回起点
            this.currentPosition = 0;
          })
        })
      
      // 动画目标元素
      Column() {
        Text('关键帧动画')
      }
      .width(100)
      .height(100)
      .backgroundColor(Color.Green)
      .translate({ x: this.currentPosition, y: this.currentPosition })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

六、动画参数

AnimateParam对象配置

{
  duration: number,      // 动画时长,单位ms
  curve: Curve,          // 动画曲线
  delay: number,         // 动画延迟
  iterations: number,    // 重复次数
  playMode: PlayMode    // 播放模式(正常/反向/交替)
}

常用动画曲线

  • linear:线性匀速
  • ease:慢快慢
  • easeIn:慢开始
  • easeOut:慢结束
  • easeInOut:慢开始和结束
  • springMotion:弹簧效果
  • responsiveSpringMotion:响应式弹簧

七、注意事项

1. UI上下文明确性

避免直接使用animateTo可能导致UI上下文不明确的问题,推荐使用:

// 推荐方式
this.getUIContext()?.animateTo({ /* 参数 */ }, () => {
  // 动画逻辑
});

// 不推荐方式  
animateTo({ /* 参数 */ }, () => {
  // 动画逻辑
});

2. 性能优化建议

  • 避免在动画中修改大量无关属性
  • 使用合适的动画时长(通常200-500ms)
  • 选择合适的动画曲线以减少视觉疲劳
  • 对复杂动画使用keyframeAnimateTo分段处理

3. 内存管理

  • 及时取消不必要的动画
  • 避免在销毁的组件上执行动画
  • 使用合适的动画重复策略

4. 用户体验考虑

  • 提供动画状态反馈
  • 确保动画有明确的开始和结束状态
  • 考虑动画的可中断性和可逆性
  • 适配不同的设备性能

八、总结

  1. animateTo适合基于状态变化的复杂动画序列
  2. animation适合简单的属性自动动画
  3. keyframeAnimateTo适合需要精细控制的关键帧动画

合理选择动画接口和配置适当的动画参数,创建出流畅、自然且性能优异的动画效果,提升应用的用户体验。

Logo

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

更多推荐