HarmonyOS Developer 动效开发指导

丶龙八夷
发布于 2023-3-27 17:09
浏览
0收藏

JS动画

组件动画

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

获取动画对象

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

/* xxx.js */
export default {
    data: {
        animation: '',
        options: {},
        frames: {}
    },
    onInit() {
        this.options = {
            duration: 1500,
        };
        this.frames = [
            {
                width: 200, height: 200,
            },
            {
                width: 300, height: 300,
            }
        ];
    },
    Show() {
        this.animation = this.$element('content').animate(this.frames, this.options); //获取动画对象
        this.animation.play();
    }
}

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

  • 使用animate方法时必须传入Keyframes和Options参数。
  • 多次调用animate方法时,采用replace策略,即最后一次调用时传入的参数生效。
设置动画参数

在获取动画对象后,通过设置参数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()
    }
}

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

  • translate、scale和rtotate的先后顺序会影响动画效果。
  • transformOrigin只对scale和rtotate起作用。

在获取动画对象后,通过设置参数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%;
  height: 100%;
}
.box{
  width: 200px;
  height: 200px;
  background-color: #ff0000;
  margin-top: 30px;
}

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

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

direction:指定动画的播放模式。

normal: 动画正向循环播放。

reverse: 动画反向循环播放。

alternate:动画交替循环播放,奇数次正向播放,偶数次反向播放。

alternate-reverse:动画反向交替循环播放,奇数次反向播放,偶数次正向播放。

插值器动画

动画动效

通过设置插值器来实现动画效果。

说明

从API Version 6 开始支持。

创建动画对象

通过createAnimator创建一个动画对象,通过设置参数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.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();
  }
}

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

  • 使用createAnimator创建动画对象时必须传入options参数。
  • begin插值起点,不设置时默认为0。
  • end插值终点,不设置时默认为1。

添加动画事件和调用接口

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

<!-- 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.js
import animator from '@ohos.animator';
import prompt from '@system.prompt';
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() {
      prompt.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() {
      prompt.showToast({
        message: 'finish'
      })
    };
    this.animation.finish(); //调用动画完成接口
  },
  cancelAnimation() {
    this.animation.cancel(); //调用动画取消接口
  },
  reverseAnimation() {
    this.animation.reverse(); //调用动画倒放接口
  }
}

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

动画帧
请求动画帧

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

runframe在调用requestAnimationFrame时传入带有timestamp参数的回调函数step,将step中的timestamp赋予起始的startTime。当timestamp与startTime的差值小于规定的时间时将再次调用requestAnimationFrame,最终动画将会停止。

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

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

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

取消动画帧

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

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

HarmonyOS Developer 动效开发指导-鸿蒙开发者社区

说明

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



文章转载自:​​https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/ui-js-animate-frame-0000001478061553-V3?catalogVersion=V3​

标签
已于2023-3-27 17:09:48修改
收藏
回复
举报
回复
    相关推荐