一. 组件动画
在组件上创建和运行动画的快捷方式。具体用法请参考通用方法。
获取动画对象
通过调用 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.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() }}
说明
● 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%;}.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(); }}
说明
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.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(); }}
说明
● 使用 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.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(); //调用动画倒放接口 }}
说明
在调用 update 接口的过程中可以使用这个接口更新动画参数,入参与 createAnimator 一致。
动画帧
请求动画帧
请求动画帧时通过 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.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); }}
说明
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.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); }}
说明
在调用该函数时需传入一个具有标识 id 的参数。