开发指导—利用组件插值器动画实现 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;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 的参数。
相关文章:
开发指导—利用组件插值器动画实现 HarmonyOS 动效
一. 组件动画 在组件上创建和运行动画的快捷方式。具体用法请参考通用方法。 获取动画对象 通过调用 animate 方法获得 animation 对象,animation 对象支持动画属性、动画方法和动画事件。 <!-- xxx.hml --><div class"container"> <di…...
树莓派入门
目录 前言系统烧录使用官方烧录工具选择操作系统选择存储卡配置 Win32DiskImager 有屏幕树莓派开机树莓派关机无屏幕树莓派开机获取树莓派IP地址通过路由器获取共享网络方式获取给树莓派配置静态IP地址查找默认网关分盘给树莓派的IP地址修改树莓派DHCP配置文件 ssh登录 让树莓派…...
算法模型嵌入式 Mendix应用的开发示例
一、前言 根据埃森哲最新一项调查,2023年67%的企业持续加大在技术方面的投入,其中数据和AI应用是重中之重。AI在企业内部应用这个话题已经保持了十多年的热度,随着ChatGPT为代表的生成式AI技术的出现,这一话题迎来又一波的高潮。…...
如何使用Cygwin编译最新版的Redis源码,生成适用于Windows的Redis
文章目录 一、准备Cygwin环境二、下载Redis源码三、编译redis-7.2.01. 执行make命令2. 重新执行make命令3. 再次执行make命令4. 将编译后的可执行文件及依赖放到同一个文件夹5. 测试编译生成的可执行程序 四、换其他redis版本重新编译1. 编译redis-7.0.122. 编译redis-6.2.133.…...
Linux 修改SSH端口
如果防火墙,或防火墙已经开启,需要先开放2222端口 firewall-cmd --add-port2222/tcp --permanent --zonepublic firewall-cmd --reload编辑文件 vim /etc/ssh/sshd_config: #Port 22 Port 2222 # 打开注释,并修改为以下值 Clien…...
Redis经典问题:缓存穿透
(笔记总结自《黑马点评》项目) 一、产生原因 用户请求的数据在缓存中和数据库中都不存在,不断发起这样的请求,给数据库带来巨大压力。 常见的解决方式有缓存空对象和布隆过滤器。 二、缓存空对象 思路:当我们客户…...
DEFORMABLE DETR: DEFORMABLE TRANSFORMERS FOR END-TO-END OBJECT DETECTION (论文解析)
DEFORMABLE DETR: DEFORMABLE TRANSFORMERS FOR END-TO-END OBJECT DETECTION 摘要1 介绍2 相关工作3 重新审视 Transformers 和 DETR4 方法4.1 用于端到端目标检测的可变形transformer4.2 Deformable Detr的其他改进和变型5 实验5.1 和DETR 比较5.2 消融实验5.3 与最先进方法的…...
网络连接评分机制之NetworkFactory
在开机时,各个提供网络连接的对象需要向ConnectivityService注册自己,并把自己所提供的网络的分值告诉ConnectivityService。 为了ConnectivityService便于统一管理,每一个具备提供网络服务的对象都需要创建一个NetworkFactory的子类对象,并利用该对象注册自己,以及提供自…...
极致精细的jmeter+ant+jenkins 搭建接口自动化测试
一、jmeter 相信大家对jmeter并不陌生哈,如果没有安装和配置环境的小伙伴,可以直接找到我哈,我发给你。 二、ant 安装ant 第一步:下载ant http://ant.apache.org/ 第二步:配置ant window中设置ant环境变量&…...
Unity物体查找方式
参考资料 cUnity中使用GameObject.Find、Transform.Find查找GameObject_思月行云的博客-CSDN博客 GameObject.Find 通过名字或路径查找游戏对象。 GameObject.Find("GameObject"); GameObject.Find("GameObject/ChildGameObject); 使用规范: 1.无法查找隐藏…...
【Spring容器的启动流程】
Spring容器的启动流程主要分为以下几个步骤: 加载配置文件:Spring容器会从指定的配置文件中读取配置信息,包括bean的定义、依赖关系、AOP切面等。 创建容器:Spring容器启动后会创建一个容器实例,容器负责管理bean的生…...
Python---字符串
字符串特点 1. 只可以存储字符串 2. 长度任意 (取决于内存大小) 3. 支持下标索引 4. 允许重复字符串存在 5. 不可以修改 (增加或删除元素等) 6. 支持for和while循环 字符串的下标索引 # 字符串的下标索引 从前向后,下标从0开始 从后向前,下标从-1开始…...
MySQL数据 - 索引
MySQL数据库 - 索引 1:什么是数据库索引?2:都有哪些类型的索引呢?3:MySQL数据库每种索引的底层实现原理,每种索引为什么这么实现?4:上面索引实现基本上是B+树,为什么不用别的数据结构呢?4-1:那为什么不是二叉树呢?4-2:为什么不是红黑树呢?4-3:为什么不是哈希索引…...
长安链BaaS服务平台调研
目录 一、菜单功能二、其他说明2.1、服务平台的部署方式2.2、链本身2.3、建链流程2.4、支持连接已部署的链2.5、链治理投票2.6、支持动态节点操作2.7、支持应用 长安链ChainMaker管理平台文档地址:https://docs.chainmaker.org.cn 一、菜单功能 菜单子菜单/功能点…...
怎么关闭php错误提示?两者方法分享
PHP程序员在开发过程中经常会遇到各种错误。为了方便查错,PHP默认会输出错误提示。但在生产环境中,这些错误提示信息不仅可能暴露你的代码结构,还会影响网站的性能和安全性。因此,关闭 PHP 的错误提示信息是一个很有必要并且很简单…...
Android Aidl跨进程通讯(三)--进阶使用
学更好的别人, 做更好的自己。 ——《微卡智享》 本文长度为2478字,预计阅读6分钟 前言 Android的AIDL使用和异常报错都已经介绍过了,今天这篇还是在原来的Demo基础上加入几个AIDL的进阶使用方法。 】 AIDL进阶使用 微卡智享 in,out,inout的使…...
vue.js+nodejs家庭个人理财收支管理系统5x6nf
本收支管理系统以vue.js作为框架,nodejs语言,B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块:用户管理、收入分类、支出分类、每日收入、每日支出等模块。 本文的组织结构如下: 1、绪论。综述了本文的研究背景…...
怎样去掉win11快捷方式的小箭头
前有创造注册表新值的方法,现在有了注册表加文件的方法 开始 先下载这个文件,里面有要用到的信息 下载 保存文件到电脑,并解压 有两个文件, 一个是 Remove_shortcut_arrow_icon.reg 一个是blank.ico 把第二个文件移动到 C:\Windows 文件夹, 然后点击打开文件, 如果提示是…...
Django项目如何配置日志文件信息
1、以dict的方式配置在settings.py中 # 日志文件简单配置LOGGING {"version": 1,"disable_existing_loggers": False,"handlers": {"file": {"level": "DEBUG","class": "logging.FileHandler&…...
遇到一个异步任务后是否会直接加入到异步队列当中
在javascript中,异步任务不会立即加入到异步队列(任务队列)中,而是根据不同的异步操作类型和执行环境,将对应的回调函数函数或事件加入到不同的队列中 javascript中常见的异步操作包括: 定时器࿱…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
