ArkUI中的显式动画(animateTo)详解

概述

ArkUI_NativeAnimateAPI_1是ArkUI提供的一组Native侧动画接口,包括显式动画、关键帧动画以及创建和销毁动画对象的功能。这些接口允许开发者通过编程方式控制动画效果,实现丰富的用户界面交互。

显式动画(animateTo)是ArkUI中一种强大的动画实现方式,它通过闭包内改变属性引起的界面变化来产生动画效果。与属性动画不同,显式动画作用于出现消失转场,是通用函数,对闭包前界面和闭包中的状态变量引起的界面之间的差异做动画。它支持多次调用和嵌套使用。

基本用法

animateTo接口的基本语法如下:

 
animateTo(value: AnimateParam, event: () => void): void 

其中:

  • value:设置动画效果相关参数
  • event:指定动效的闭包函数,在闭包函数中导致的状态变化系统会自动插入过渡动画

参数说明

AnimateParam对象包含以下可配置参数:

参数名 类型 描述
duration number 动画播放时长
curve Curve 动画曲线类型
delay number 动画延迟执行的时长
iterations number 动画播放次数
playMode PlayMode 动画播放模式
onFinish () => void 动画播放完成回调

使用示例

基础示例

以下是一个简单的animateTo使用示例:

 
@Entry
@Component
struct AnimateToExample {
  @State widthSize: number = 250
  @State heightSize: number = 100
  @State rotateAngle: number = 0
  private flag: boolean = true

  build() {
    Column() {
      Button('change size').width(this.widthSize).height(this.heightSize).margin(30).onClick(() => {
        if (this.flag) {
          animateTo({
            duration: 2000,
            curve: Curve.EaseOut,
            iterations: 3,
            playMode: PlayMode.Normal,
            onFinish: () => {
              console.info('play end')
            }
          }, () => {
            this.widthSize = 150
            this.heightSize = 60
          })
        } else {
          animateTo({}, () => {
            this.widthSize = 250
            this.heightSize = 100
          })
        }
        this.flag = !this.flag
      })
      Button('stop rotating')
        .margin(50)
        .rotate({
          x: 0,
          y: 0,
          z: 1,
          angle: this.rotateAngle
        })
        .onAppear(() => {
          // 组件出现时开始做动画
          animateTo({
            duration: 1200,
            curve: Curve.Friction,
            delay: 500,
            iterations: -1,
            // 设置-1表示动画无限循环
            playMode: PlayMode.Alternate,
            expectedFrameRateRange: { min: 10, max: 120, expected: 60, }
          }, () => {
            this.rotateAngle = 90
          })
        }).onClick(() => {
        animateTo({ duration: 0 },
          () => {
            // this.rotateAngle之前为90,在duration为0的动画中修改属性,可以停止该属性之前的动画,按新设置的属性显示
            this.rotateAngle = 0
          })
      })
    }.width('100%').margin({ top: 5 })
  }
}

 

组件消失动画示例

animateTo也可以用于实现组件消失时的动画效果:

 
@Entry
@Component
struct AttrAnimationExample {
  @State heightSize: number = 100;
  @State isShow: boolean = true;
  @State count: number = 0;
  private isToBottom: boolean =
    true;

  // 向下
  build() {
    Column() {
      if (this.isShow) {
        Column().width(200).height(this.heightSize).backgroundColor('blue').onClick(() => {
          animateTo({
            duration: 2000,
            curve: Curve.EaseOut,
            iterations: 1,
            playMode: PlayMode.Normal,
            onFinish: () => {
              this.count--;
              if (this.count == 0 &&
                !this.isToBottom) {
                // 组件只有在向下做完动画才会消失
                this.isShow = false;
              }
            }
          }, () => {
            this.count++;
            if (this.isToBottom) {
              this.heightSize = 60;
            } else {
              this.heightSize = 100;
            }
            this.isToBottom = !this.isToBottom;
          })
        })
      }
    }.width('100%').height('100%').margin({ top: 5 }).justifyContent(FlexAlign.End)
  }
}

官网给的效果图是这样的

但我自己实验后发现并没有回弹的这个效果,

 

实验设备为 

HUAWEI Mate 60 Pro

OpenHarmony 5.0.1.120 (API 17)

 

动画曲线

animateTo支持多种动画曲线,可以通过curve参数指定:

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

@Entry
@Component
struct AnimateToDemo {
  @State animate: boolean = false;
  @State rotateValue: number = 0;
  @State translateX: number = 0;
  @State opacityValue: number = 1;

  build() {
    Row() {
      Column() {
      }
      .rotate({ angle: this.rotateValue })
      .backgroundColor('#317AF7')
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .borderRadius(30)
      .onClick(() => {
        this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
          this.animate = !this.animate;
          this.rotateValue = this.animate ? 90 : 0;
          this.opacityValue = this.animate ? 0.6 : 1;
          this.translateX = this.animate ? 50 : 0;
        })
      })

      Column() {
      }
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
    }.width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

 

性能优化

为了优化动画性能,animateTo提供了一些高级参数:

 
animateTo({ expectedFrameRateRange: { min: 10, max: 120, expected: 60, } }, () => { // 动画代码 }) 

状态管理V2中的注意事项

在状态管理V2中使用animateTo时需要注意一些特殊情况:

@Entry
@ComponentV2
struct Index {
  @Local w: number = 50;
  @Local h: number = 50;
  @Local message: string = 'Hello';

  build() {
    Column() {
      Button('change size').margin(20).onClick(() => {
        this.w = 100;
        this.h = 100;
        this.message = 'Hello World';
        animateTo({ duration: 1000 }, () => {
          this.w = 200;
          this.h = 200;
          this.message = 'Hello ArkUI';
        })
      })
      Column() {
        Text(`${this.message}`)
      }.backgroundColor('#ff17a98d').width(this.w).height(this.h)
    }
  }
} 

可以通过以下方式获得预期效果:

@Entry
@ComponentV2
struct Index {
  @Local w: number = 50;
  @Local h: number = 50;
  @Local message: string = 'Hello';

  build() {
    Column() {
      Button('change size').margin(20).onClick(() => {
        this.w = 100;
        this.h = 100;
        this.message = 'Hello Word';
        animateToImmediately({ duration: 0 }, () => {
        })
        animateTo({ duration: 1000 }, () => {
          this.w = 200;
          this.h = 200;
          this.message = 'Hello ArkUI';
        })
      })
      Column() {
        Text(`${this.message}`)
      }.backgroundColor('#ff17a98d').width(this.w).height(this.h)
    }
  }
}

 

动画衔接

animateTo支持动画与动画、手势与动画之间的自然过渡:

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

class SetSlt {
  isAnimation: boolean = true

  set(): void {
    this.isAnimation = !this.isAnimation;
  }
}

@Entry
@Component
struct AnimationToAnimationDemo {
  @State SetAnimation: SetSlt = new SetSlt();

  build() {
    Column() {
      Text('ArkUI')
        .fontWeight(FontWeight.Bold)
        .fontSize(12)
        .fontColor(Color.White)
        .textAlign(TextAlign.Center)
        .borderRadius(10)
        .backgroundColor(0xf56c6c)
        .width(100)
        .height(100)
        .scale({ x: this.SetAnimation.isAnimation ? 2 : 1, y: this.SetAnimation.isAnimation ? 2 : 1 })
        .animation({ curve: curves.springMotion(0.4, 0.8) })
      Button('Click').margin({ top: 200 }).onClick(() => {
        this.SetAnimation.set()
      })
    }.width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

 

显式立即动画(animateToImmediately)

animateToImmediately是animateTo的变体,可以立即执行闭包代码中状态变化导致的过渡动效:

@Entry
@Component
struct AnimateToImmediatelyExample {
  @State widthSize: number = 250
  @State heightSize: number = 100
  @State opacitySize: number = 0
  private flag: boolean = true

  build() {
    Column() {
      Column().width(this.widthSize).height(this.heightSize).backgroundColor(Color.Green).opacity(this.opacitySize)
      Button('change size').margin(30).onClick(() => {
        if (this.flag) {
         animateToImmediately({ delay: 0, duration: 1000 }, () => {
            this.opacitySize = 1
          })
          animateTo({ delay: 1000, duration: 1000 }, () => {
            this.widthSize = 150
            this.heightSize = 60
          })
        } else {
          animateToImmediately({ delay: 0, duration: 1000 }, () => {
            this.widthSize = 250
            this.heightSize = 100
          })
          animateTo({ delay: 1000, duration: 1000 }, () => {
            this.opacitySize = 0
          })
        }
        this.flag = !this.flag
      })
    }.width('100%').margin({ top: 5 })
  }
}

 

总结

animateTo是ArkUI中功能强大的显式动画接口,它通过对比闭包执行前后的状态差异来自动生成过渡动画。开发者可以通过配置动画参数、曲线类型等实现各种复杂的动画效果。同时,animateTo支持嵌套调用、动画衔接等高级特性,能够满足大多数UI动画需求。在使用时需要注意状态管理V2中的特殊情况,并合理使用animateToImmediately等变体来优化动画性能。

----

啰嗦一句:官网代码也不一定百分百正确,也可能是设备系统更新后官网示例没有更新。一切以实际为准

Logo

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

更多推荐