开发指导—利用组件&插值器动画实现HarmonyOS动效
一. 组件动画
在组件上创建和运行动画的快捷方式。具体用法请参考通用方法。
获取动画对象
通过调用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;
#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.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.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 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%;coral;">
</canvas>
<div style="width: 50px;height: 50px;border-radius: 25px;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);
}
}

说明
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%;coral;">
</canvas>
<div style="width: 50px;height: 50px;border-radius: 25px;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);
}
}

说明
在调用该函数时需传入一个具有标识id的参数。
开发指导—利用组件&插值器动画实现HarmonyOS动效的更多相关文章
- js抛物线动画——加入购物车动效
参考文章:http://www.zhangxinxu.com/wordpress/2013/12/javascript-js-元素-抛物线-运动-动画/ parapola.js /*! * by zh ...
- 实现一个带有动效的 React 弹窗组件
我们在写一些 UI 组件时,若不考虑动效,就很容易实现,主要就是有无的切换(类似于 Vue 中的 v-if 属性)或者可见性的切换(类似于 Vue 中的 v-show 属性). 1. 没有动效的弹窗 ...
- 乘风破浪,Windows11设计和开发指导,全新图标字体和云母材质
Windows11全新的布局设计 Windows 11全新的布局设计已设计为支持现代应用体验.渐进的圆角.嵌套元素和一致的排水沟相结合,营造出柔和.平静.平易近人的效果,强调目的的统一和易用性. ht ...
- 安卓开发_浅谈Android动画(四)
Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1. ValueAnimator 基本属 ...
- Android开发——构建自定义组件
Android中,你的应用程序程序与View类组件有着一种固定的联系,例如按钮(Button). 文本框(TextView), 可编辑文本框(EditText), 列表框(ListView), 复选框 ...
- QtQuick桌面应用程序开发指导 3)达到UI而功能_B 4)动态管理Note物_A
3.2 把Page Item和Marker Item绑定 之前我们实现了PagePanel组件, 使用了三个state来切换Page组件的opacity属性; 这一步我们会使用Marker和Marke ...
- 《C++游戏开发》笔记十一 平滑动画:不再颤抖的小雪花
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9430645 作者:七十一雾央 新浪微博:http:/ ...
- iOS组件化开发· 什么是组件化
越来越多公司,开始了组件化,你还要等到什么时候...... 说到开发模式,我们最熟知的开发模式 MVC 或者最近比较热门的MVVM.但是我今天说的组件化的开发,其实MVC不是一类的.它其实是····· ...
- vue开发可复用组件
组件,是一个具有一定功能,且不同组件间功能相对独立的模块.高内聚.低耦合. 开发可复用性的组件应遵循以下原则: 1.规范化命名:组件的命名应该跟业务无关,而是依据组件的功能命名. 2.数据扁平 ...
- script标签引入vue方式开发如何写组件
title: script标签引入vue方式开发如何写组件 date: 2020-05-08 sidebarDepth: 2 tags: vue 组件 script 标签 categories: vu ...
随机推荐
- 【Azure Developer】在使用中国区 Azure AD B2C时, AUTHORITY的值是什么呢?
问题描述 使用MSAL4J的SDK调用(源码地址:https://github.com/Azure-Samples/ms-identity-msal-java-samples/tree/main/3. ...
- 微信小程序开发:接入阿里云人像动漫化api接口
前面我已经把腾讯云的人像转动漫化接口接到了我的小程序里,但是和阿里云的对比后,发现阿里云的效果会更好一些,且支持更多特效,如下: 我比较喜欢这个3D特效风格,动画3D也可以,大家拭目以待. 话说上次接 ...
- mysql-对应删除 dict 脚本
-- 1. 此 dict 是在不同租户下的数据字典,查询时需要根据 departid 进行分类查询 -- 2. 删除dict, dict分类主表类型与挂载的子表数据 -- 3. 通过查询到的主表的 g ...
- 快速带你入门css
css复习笔记 1. css样式值 1.1 文字样式 1 p{ 2 font-size: 30px;/*设置文字大小*/ 3 font-weight: bold;/*文字加粗*/ 4 font-sty ...
- APP限制录屏怎么办?如何绕过APP录屏限制和截图限制-支持安卓和IOS
简要:互联网越来越发达,衍生了很多形形色色的app,商家为了防止app资源被传播,因此在用户截取屏幕操作或者录屏操作时会警告用户并前会禁止用户的这一操作行为. 那么有没有办法解决呢?有人说可以用投屏. ...
- Python函数对象与闭包函数
[一]函数对象 函数对象指的是函数可以被当做 数据 来处理,具体可以分为四个方面的使用 [1]函数可以被引用 def add(x,y): return x + y func = add res = f ...
- Dreamweaver基础教程:系列介绍
目录 前言 Dreamweaver 软件介绍 软件安装 学习支持 相关资料 前言 我一直对前端的一些技术比较感兴趣,之前有用过GitHub上的开源项目部署了自己的导航网站猿导航,但并没有系统的去深入学 ...
- c语言中内存分配malloc,calloc,realloc函数的区别和联系
一 概念: A malloc() 在内存的动态存储区中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址 B calloc() 与malloc相似,参数size ...
- day28--Java泛型01
Java泛型01 1.泛型的理解和好处 看一个需求: 请编写程序,在ArrayList中添加三个Dog对象 Dog对象含有name和age,并输出name和age(要求使用getXXX()) 先用传统 ...
- JSF之Action 与ActionListener的区别
事件 检验 参数 事件产生 页面跳转 Action 有 无参数,不传入当前控件,有返回值 当铵钮被单击时产生事件.提交表单 返回页面---根据配置文件跳转 ActionLis ...