开发指导—利用组件&插值器动画实现 HarmonyOS 鸿蒙Next动效

开发指导—利用组件&插值器动画实现 HarmonyOS 鸿蒙Next动效 一. 组件动画

在组件上创建和运行动画的快捷方式。具体用法请参考通用方法

获取动画对象

通过调用 animate 方法获得 animation 对象,animation 对象支持动画属性、动画方法和动画事件。

<!-- xxx.hml -->
<div class="container">
    <div id="content" class="box" onclick="Show">
    </div>
</div>
/* xxx.css */
.container {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
}
.box{
  width: 200px;
  height: 200px;
  background-color: #ff0000;
  margin-top: 30px;
}
/* xxx.js */
export default {
  data: {
    animation: '',
  },
  onInit() {
  },
  onShow() {
    var options = {
      duration: 1500,
    };
    var frames = [
      {
        width:200,
        height:200,
      },
      {
        width:300,
        height:300,
      }
    ];
    this.animation = this.$element('content').animate(frames, options);
  },
  Show() {
    this.animation.play();
  }
}

说明

● 使用 animate 方法时必须传入 Keyframes 和 Options 参数。

● 多次调用 animate 方法时,采用 replace 策略,即最后一次调用时传入的参数生效。

设置动画参数

在获取动画对象后,通过设置参数 Keyframes 设置动画在组件上的样式。

/* xxx.js */
export default {
  data: {
    animation: '',
    keyframes:{},
    options:{}
  },
  onInit() {
    this.options = {
      duration: 4000,
    }
    this.keyframes = [
    {
      transform: {
        translate: '-120px -0px',
        scale: 1,
        rotate: 0
      },
      transformOrigin: '100px 100px',
      offset: 0.0,
      width: 200,
      height: 200
     },
     {
      transform: {
        translate: '120px 0px',
        scale: 1.5,
        rotate: 90
      },
      transformOrigin: '100px 100px',
      offset: 1.0,
      width: 300,
      height: 300
     }
    ]
  },
  Show() {
    this.animation = this.$element('content').animate(this.keyframes, this.options)
    this.animation.play()
  }
}

说明

● translate、scale 和 rtotate 的先后顺序会影响动画效果。

● transformOrigin 只对 scale 和 rtotate 起作用。

在获取动画对象后,通过设置参数 Options 来设置动画的属性。

/* xxx.js */
export default {
  data: {
    animation: ''
  },
  onInit() {
  },
  onShow() {
    var options = {
      duration: 1500,
      easing: 'ease-in',
      delay: 5,
      iterations: 2,
      direction: 'normal',
    };
    var frames = [
      {
        transform: {
          translate: '-150px -0px'
        }
      },
      {
        transform: {
          translate: '150px 0px'
        }
      }
    ];
    this.animation = this.$element('content').animate(frames, options);
  },
  Show() {
    this.animation.play();
  }
}

二. 插值器动画

动画动效

通过设置插值器来实现动画效果。(从 API Version 6 开始支持。)

创建动画对象

通过 createAnimator 创建一个动画对象,通过设置参数 options 来设置动画的属性。

/* xxx.js */
import animator from '@ohos.animator';
export default {
  data: {
    translateVal: 0,
    animation: null
  },
  onInit() {},
  onShow(){
    var options = {
      duration: 3000,
      easing:"friction",
      delay:"1000",
      fill: 'forwards',
      direction:'alternate',
      iterations: 2,
      begin: 0,
      end: 180
    };//设置参数
    this.animation = animator.createAnimator(options)//创建动画
  },
  playAnimation() {
    var _this = this;
    this.animation.onframe = function(value) {
      _this.translateVal= value
    };
    this.animation.play();
  }
}

说明

● 使用 createAnimator 创建动画对象时必须传入 options 参数。

● begin 插值起点,不设置时默认为 0。

● end 插值终点,不设置时默认为 1。

添加动画事件和调用接口

animator 支持事件和接口,可以通过添加 frame、cancel、repeat、finish 事件和调用 update、play、pause、cancel、reverse、finish 接口自定义动画效果。animator 支持的事件和接口具体见动画中的createAnimator

/* xxx.js */
import animator from '@ohos.animator';
import promptAction from '@ohos.promptAction';
export default {
  data: {
    scaleVal:1,
    DivWidth:200,
    DivHeight:200,
    translateVal:0,
    animation: null
  },
  onInit() {
    var options = {
      duration: 3000,
      fill: 'forwards',
      begin: 200,
      end: 270
    };
    this.animation = animator.createAnimator(options);
  },
  onShow() {
    var _this= this;
    //添加动画重放事件
    this.animation.onrepeat = function() {
      promptAction.showToast({
        message: 'repeat'
      });
      var repeatoptions = {
        duration: 2000,
        iterations: 1,
        direction: 'alternate',
        begin: 180,
        end: 240
      };
      _this.animation.update(repeatoptions);
      _this.animation.play();
    };
  },
  playAnimation() {
    var _this= this;
    //添加动画逐帧插值回调事件
    this.animation.onframe = function(value) {
      _this.scaleVal= value/150,
      _this.DivWidth = value,
      _this.DivHeight = value,
      _this.translateVal = value-180
    };
    this.animation.play();
  },
  updateAnimation() {
    var newoptions = {
      duration: 5000,
      iterations: 2,
      begin: 120,
      end: 180
    };
    this.animation.update(newoptions);
    this.animation.play();//调用动画播放接口
  },
  pauseAnimation() {
    this.animation.pause();//调用动画暂停接口
  },
  finishAnimation() {
    var _this= this;
    //添加动画完成事件
    this.animation.onfinish = function() {
      promptAction.showToast({
        message: 'finish'
      })
    };
    this.animation.finish(); //调用动画完成接口
  },
  cancelAnimation() {
    this.animation.cancel(); //调用动画取消接口
  },
  reverseAnimation() {
    this.animation.reverse(); //调用动画倒放接口
  }
}

说明

● 在调用 update 接口的过程中可以使用这个接口更新动画参数,入参与 createAnimator 一致。

动画帧

请求动画帧

请求动画帧时通过 requestAnimationFrame 函数逐帧回调,在调用该函数时传入一个回调函数。

/* xxx.js */
export default {
  data: {
    timer: null,
    left: 0,
    top: 0,
    flag: true,
    animation: null,
    startTime: 0,
  },
  onShow() {
    var test = this.$element("mycanvas");
    var ctx = test.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(300, 300);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "red";
    ctx.stroke();
  },
  runframe() {
    this.left = 0;
    this.top = 0;
    this.flag = true;
    this.animation = requestAnimationFrame(this.step);
  },
  step(timestamp) {
    if (this.flag) {
      this.left += 5;
      this.top += 5;
      if (this.startTime == 0) {
        this.startTime = timestamp;
      }
      var elapsed = timestamp - this.startTime;
      if (elapsed < 500) {
        console.log('callback step timestamp: ' + timestamp);
        this.animation = requestAnimationFrame(this.step);
      }
    } else {
      this.left -= 5;
      this.top -= 5;
      this.animation = requestAnimationFrame(this.step);
    }
    if (this.left == 250 || this.left == 0) {
      this.flag = !this.flag
    }
  },
  onDestroy() {
    cancelAnimationFrame(this.animation);
  }
}

说明

● requestAnimationFrame 函数在调用回调函数时在第一个参数位置传入 timestamp 时间戳,表示 requestAnimationFrame 开始去执行回调函数的时刻。

取消动画帧

通过 cancelAnimationFrame 函数取消逐帧回调,在调用 cancelAnimationFrame 函数时取消 requestAnimationFrame 函数的请求。

/* xxx.js */
export default {
  data: {
    timer: null,
    left: 0,
    top: 0,
    flag: true,
    animation: null
  },
  onShow() {
    var test = this.$element("mycanvas");
    var ctx = test.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(300, 300);
    ctx.lineWidth = 5;
    ctx.strokeStyle = "red";
    ctx.stroke();
  },
  runframe() {
    this.left = 0;
    this.top = 0;
    this.flag = true;
    this.animation = requestAnimationFrame(this.step);
  },
  step(timestamp) {
    if (this.flag) {
      this.left += 5;
      this.top += 5;
      this.animation = requestAnimationFrame(this.step);
    } else {
      this.left -= 5;
      this.top -= 5;
      this.animation = requestAnimationFrame(this.step);
    }
    if (this.left == 250 || this.left == 0) {
      this.flag = !this.flag
    }
  },
  onDestroy() {
    cancelAnimationFrame(this.animation);
  }
}

说明

● 在调用该函数时需传入一个具有标识 id 的参数。


更多关于开发指导—利用组件&插值器动画实现 HarmonyOS 鸿蒙Next动效的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

xxx.js

更多关于开发指导—利用组件&插值器动画实现 HarmonyOS 鸿蒙Next动效的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,利用组件和插值器实现动效,首先选择适合的动画组件如AnimatorTransition,然后定义插值器如LinearInterpolatorAccelerateDecelerateInterpolator来控制动画速度变化。通过ValueAnimator设置属性动画,结合插值器实现平滑过渡。最后,将动画绑定到UI组件上,启动动画以展示流畅的视觉动效。

回到顶部