Development guidance—Using component & interpolator animation to implement HarmonyOS animation

1. Component animation

Shortcut to create and run animations on components. Please refer to the general method for specific usage .

Get animation object

The animation object is obtained by calling the animate method. The animation object supports animation properties, animation methods and animation events.

<!-- 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();  }}

illustrate

● Keyframes and Options parameters must be passed in when using the animate method.

● When the animate method is called multiple times, the replace strategy is adopted, that is, the parameters passed in during the last call take effect.

Set animation parameters

After obtaining the animation object, set the style of the animation on the component by setting the parameter Keyframes.

<!-- 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%;  height: 100%;}.box{
   
     width: 200px;  height: 200px;  background-color: #ff0000;  margin-top: 30px;}

/* 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()  }}

illustrate

● The order of translate, scale and rtotate will affect the animation effect.

● transformOrigin only works on scale and rtotate.

After obtaining the animation object, set the properties of the animation by setting the parameter Options.

<!-- 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,              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();  }}

illustrate

direction: Specifies the animation playback mode.

normal: The animation loops forward.

reverse: The animation plays in reverse loop.

alternate: The animation plays alternately in a loop, playing forward for odd numbers and backward for even numbers.

alternate-reverse: The animation is played in an alternate loop in reverse directions, with odd numbers of reverse playbacks and even number of forward playbacks.

2. Interpolator animation

Animation effects

Animation effects are achieved by setting interpolators. (Supported starting from API Version 6.)

Create animated objects

Create an animation object through createAnimator, and set the animation properties by setting parameter options.

<!-- xxx.hml --><div class="container">  <div style="width: 300px;height: 300px;margin-top: 100px;background: linear-gradient(pink, purple);transform: translate({
   
   {translateVal}});">  </div>  <div class="row">    <button type="capsule" value="play" onclick="playAnimation"></button>  </div></div>

/* xxx.css */.container {
   
     width:100%;  height:100%;  flex-direction: column;  align-items: center;  justify-content: center;}button{
   
     width: 200px;}.row{
   
     width: 65%;  height: 100px;  align-items: center;  justify-content: space-between;  margin-top: 50px;  margin-left: 260px;}

// xxx.jsimport 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();  }}

illustrate

● When using createAnimator to create an animation object, the options parameter must be passed in.

● begin interpolation starting point, default is 0 if not set.

● end is the end point of interpolation. If not set, the default is 1.

Add animation events and calling interfaces

Animator supports events and interfaces. You can customize animation effects by adding frame, cancel, repeat, and finish events and calling update, play, pause, cancel, reverse, and finish interfaces. For details about the events and interfaces supported by animator, see createAnimator in animation .

<!-- xxx.hml --><div style="flex-direction: column;align-items: center;width: 100%;height: 100%;">  <div style="width:200px;height: 200px;margin-top: 100px;background: linear-gradient(#b30d29, #dcac1b);  transform: scale({
   
   {scaleVal}});"></div>  <div style="width: {
   
   {DivWidth}};height: {
   
   {DivHeight}};margin-top: 200px;  background: linear-gradient(pink, purple);margin-top: 200px;transform:translateY({
   
   {translateVal}});">  </div>  <div class="row">    <button type="capsule" value="play" onclick="playAnimation"></button>    <button type="capsule" value="update" onclick="updateAnimation"></button>  </div>  <div class="row1">    <button type="capsule" value="pause" onclick="pauseAnimation"></button>    <button type="capsule" value="finish" onclick="finishAnimation"></button>  </div>  <div class="row2">    <button type="capsule" value="cancel" onclick="cancelAnimation"></button>    <button type="capsule" value="reverse" onclick="reverseAnimation"></button>  </div></div>

/* xxx.css */button{
   
     width: 200px;}.row{
   
     width: 65%;  height: 100px;  align-items: center;  justify-content: space-between;  margin-top: 150px;  position: fixed;  top: 52%;  left: 120px;}.row1{
   
     width: 65%;  height: 100px;  align-items: center;  justify-content: space-between;  margin-top: 120px;  position: fixed;  top: 65%;  left: 120px;}.row2{
   
     width: 65%;  height: 100px;  align-items: center;  justify-content: space-between;  margin-top: 100px;  position: fixed;  top: 75%;  left: 120px;}

// xxx.jsimport 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(); //调用动画倒放接口  }}

illustrate

In the process of calling the update interface, you can use this interface to update the animation parameters, consistent with those involved in createAnimator.

Animation frames

Request animation frames

When requesting animation frames, call back frame by frame through the requestAnimationFrame function, and pass in a callback function when calling this function.

When runframe calls requestAnimationFrame, it passes in the callback function step with timestamp parameter, and assigns the timestamp in step to the initial startTime. When the difference between timestamp and startTime is less than the specified time, requestAnimationFrame will be called again, and eventually the animation will stop.

<!-- xxx.hml --><div class="container">  <tabs onchange="changecontent">    <tab-content>      <div class="container">        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">          </canvas>          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {
   
   {left}};top: {
   
   {top}};">          </div>        </stack>        <button type="capsule" value="play" onclick="runframe"></button>      </div>    </tab-content>  </tabs></div>

/* xxx.css */.container {
   
     flex-direction: column;  justify-content: center;  align-items: center;  width: 100%;  height: 100%;}button{
   
     width: 300px;}

// xxx.jsexport 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);    }}

illustrate

The requestAnimationFrame function passes in the timestamp timestamp in the first parameter position when calling the callback function, indicating the moment when requestAnimationFrame starts executing the callback function.

Cancel animation frame

Cancel the frame-by-frame callback through the cancelAnimationFrame function, and cancel the requestAnimationFrame function when calling the cancelAnimationFrame function.

<!-- xxx.hml --><div class="container">  <tabs onchange="changecontent">    <tab-content>      <div class="container">        <stack style="width: 300px;height: 300px;margin-top: 100px;margin-bottom: 100px;">          <canvas id="mycanvas" style="width: 100%;height: 100%;background-color: coral;">          </canvas>          <div style="width: 50px;height: 50px;border-radius: 25px;background-color: indigo;position: absolute;left: {
   
   {left}};top: {
   
   {top}};">          </div>        </stack>        <button type="capsule" value="play" onclick="runframe"></button>      </div>    </tab-content>  </tabs></div>

/* xxx.css */.container {
   
     flex-direction: column;  justify-content: center;  align-items: center;  width: 100%;  height: 100%;}button{
   
     width: 300px;}

// xxx.jsexport 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);  }}

illustrate

When calling this function, a parameter with an identification id needs to be passed in.

Guess you like

Origin blog.csdn.net/HarmonyOSDev/article/details/132688143