OpenHarmony动效示例-如何使用animateTo实现显式动画。

介绍

利用ArkUI组件不仅可以实现局部属性变化产生的属性动画,也可以实现父组件属性变化引起子组件产生过渡效果式的全局动画即显式动画。效果如图所示:

相关概念

  • 显式动画:提供全局animateTo显式动画接口来指定有闭包代码导致的状态变化插入过渡动画效果。
  • 属性动画:组件的通用属性发生变化时,可以创建属性动画进行渐变,提升用户体验。
  • Slider:滑动条组件,用来快速调节设置值,如音量、亮度等。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets                // 代码区
│  ├──common
│  │  └──constants
│  │     └──Const.ets                // 常量类
│  ├──entryability
│  │  └──EntryAbility.ts             // 程序入口类
│  ├──pages
│  │  └──Index.ets                   // 动效页面入口
│  ├──view
│  │  ├──AnimationWidgets.ets        // 动画组件
│  │  ├──CountController.ets         // 图标数量控制组件
│  │  └──IconAnimation.ets           // 图标属性动画组件
│  └──viewmodel
│     ├──IconItem.ets                // 图标类
│     ├──IconsModel.ets              // 图标数据模型
│     └──Point.ets                   // 图标坐标类
└──entry/src/main/resources          // 资源文件

页面入口

页面入口由AnimationWidgets(动效组件)、CountController(动效图标数量控制组件)组成。

其中CountController通过Slider滑动控制quantity(动效图标数量);AnimationWidgets根据quantity展示相应数量的图标,点击组件按钮后通过在animateTo的event闭包函数中改变mainFlag状态,跟mainFlag相关的样式属性的变化都会产生动画效果,代码如下所示:

// Index.ets
@Entry
@Component
struct Index {@State quantity: number = Common.IMAGES_MIN;@Provide iconModel: IconsModel = new IconsModel(this.quantity, Common.OFFSET_RADIUS);build() {Column() {// 动画组件AnimationWidgets({quantity: $quantity})// 图标数量控制组件CountController({quantity: $quantity})}
...}
}

CountController组件通过Slilder滑动控制动效图标的数量,最少3个图标,最多6个图标,示例代码如下所示:

// CountController.ets
@Component
export struct CountController {@Link quantity: number;build() {Column() {Row() {Text($r('app.string.count')).textStyle()Text(this.quantity).textStyle()}...Slider({value: this.quantity,min: Common.IMAGES_MIN,max: Common.IMAGES_TOTAL,step: 1,style: SliderStyle.InSet}).blockColor(Color.White).selectedColor('#007DFF').showSteps(true).trackThickness($r('app.float.size_20')).onChange((value: number) => {this.quantity = value;})...}}
}

显式动画

点击AnimationWidgets组件的中心图标,调用animateTo方法,在event回调方法中改变状态,从而对组件本身产生缩放动画,和图标位置变化的动画效果,效果如下所示:

在animationTo的回调中修改mainFlag状态,所有跟mainFlag状态相关的属性变化都会产生过渡动画效果。代码如下所示:

// AnimationWidgets.ets
import { IconsModel } from '../viewmodel/IconsModel';
import { IconAnimation } from './IconAnimation';
import Common from '../common/constants/Const';
import IconItem from '../viewmodel/IconItem';@Component
export struct AnimationWidgets {@State mainFlag: boolean = false;@Link @Watch('onQuantityChange') quantity: number;@Consume iconModel: IconsModel;onQuantityChange() {this.iconModel.addImage(this.quantity);}aboutToAppear() {this.onQuantityChange();}animate() {animateTo({delay: Common.DELAY_10,tempo: Common.TEMPO,iterations: 1,duration: Common.DURATION_500,curve: Curve.Smooth,playMode: PlayMode.Normal}, () => {this.mainFlag = !this.mainFlag;})}build() {Stack() {Stack() {ForEach(this.iconModel.imagerArr, (item: IconItem) => {IconAnimation({item: item,mainFlag: $mainFlag})}, (item: IconItem) => JSON.stringify(item.index))}.width(Common.DEFAULT_FULL_WIDTH).height(Common.DEFAULT_FULL_HEIGHT).rotate({x: 0,y: 0,z: 1,angle: this.mainFlag ? Common.ROTATE_ANGLE_360 : 0})Image(this.mainFlag? $r("app.media.imgActive"): $r("app.media.imgInit")).width($r('app.float.size_64')).height($r('app.float.size_64')).objectFit(ImageFit.Contain).scale({x: this.mainFlag ? Common.INIT_SCALE : 1,y: this.mainFlag ? Common.INIT_SCALE : 1}).onClick(() => {this.iconModel.reset();this.animate();})Text($r('app.string.please_click_button')).fontSize($r('app.float.size_16')).opacity(Common.OPACITY_06).fontColor($r('app.color.fontGrayColor')).fontWeight(Common.FONT_WEIGHT_500).margin({top: $r('app.float.size_100')})}.width(Common.DEFAULT_FULL_WIDTH).layoutWeight(1)}
}

属性动画

组件的通用属性发生变化时,可以创建属性动画进行渐变,提升用户体验。示例效果如下所示:


当组件由animation动画属性修饰时,如果自身属性发生变化会产生过渡动画效果。本示例中当点击小图标时会触发自身clicked状态的变化,所有跟clicked相关的属性变化(如translate、rotate、scale、opacity)都会被增加动画效果。代码如下所示:

// IconAnimation.ets
export struct IconAnimation {@Link mainFlag: boolean;@ObjectLink item: IconItem;build() {Image(this.item.image).width(Common.ICON_WIDTH).height(Common.ICON_HEIGHT).objectFit(ImageFit.Contain).translate(this.mainFlag? { x: this.item.point.x, y: this.item.point.y }: { x: 0, y: 0 }).rotate({x: 0,y: 1,z: 0,angle: this.item.clicked ? Common.ROTATE_ANGLE_360 : 0}).scale(this.item.clicked? { x: Common.SCALE_RATIO, y: Common.SCALE_RATIO }: { x: 1, y: 1 }).opacity(this.item.clicked ? Common.OPACITY_06 : 1).onClick(() => {this.item.clicked = !this.item.clicked;}).animation({delay: Common.DELAY_10,duration: Common.DURATION_1000,iterations: 1,curve: Curve.Smooth,playMode: PlayMode.Normal})}
}

根据图标数量计算图标位置代码如下所示:

// IconsModel.ets
import Common from '../common/constants/Const';
import IconItem from './IconItem';
import Point from './Point';const TWO_PI: number = 2 * Math.PI;@Observed
export class IconsModel {public imagerArr: Array<IconItem> = [];private num: number = Common.IMAGES_MIN;private radius: number;constructor(num: number, radius: number) {this.radius = radius;this.addImage(num);}public addImage(num: number) {this.num = num;if (this.imagerArr.length == num) {return;}if (this.imagerArr.length > num) {this.imagerArr.splice(num, this.imagerArr.length - num);} else {for (let i = this.imagerArr.length; i < num; i++) {const point = this.genPointByIndex(i);this.imagerArr.push(new IconItem(i, Common.IMAGE_RESOURCE[i], false, point));}}this.refreshPoint(num);}public refreshPoint(num: number) {for (let i = 0; i < num; i++) {this.imagerArr[i].point = this.genPointByIndex(i);}}public genPointByIndex(index: number): Point {const x = this.radius * Math.cos(TWO_PI * index / this.num);const y = this.radius * Math.sin(TWO_PI * index / this.num);return new Point(x, y);}public reset() {for (let i = 0; i < this.num; i++) {if (this.imagerArr[i].clicked) {this.imagerArr[i].clicked = false;}}}
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 如何使用animateTo实现显式动画。
  2. 如何使用animation为组件添加属性动画。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等…视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF

在这里插入图片描述

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. .……

在这里插入图片描述


二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

在这里插入图片描述

三、如何快速入门?《鸿蒙基础入门学习指南》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. .……

在这里插入图片描述


四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. .……

在这里插入图片描述


五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 7.网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. .……

在这里插入图片描述


更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/578136.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS 应用开发之启动/停止本地PageAbility

启动本地PageAbility PageAbility相关的能力通过featureAbility提供&#xff0c;启动本地Ability通过featureAbility中的startAbility接口实现。 表1 featureAbility接口说明 接口名接口描述startAbility(parameter: StartAbilityParameter)启动Ability。startAbilityForRes…

论文笔记:TALK LIKE A GRAPH: ENCODING GRAPHS FORLARGE LANGUAGE MODELS

ICLR 2024&#xff0c;reviewer评分 6666 1 intro 1.1 背景 当下LLM的限制 限制1&#xff1a;对非结构化文本的依赖 ——>模型有时会错过明显的逻辑推理或产生错误的结论限制2&#xff1a;LLMs本质上受到它们训练时间的限制&#xff0c;将“最新”信息纳入到不断变化的世…

如何保证redis里的数据都是热点数据

MySQL 里有 2000w 数据&#xff0c;Redis 中只存 20w 的数据&#xff0c;如何保证 redis 中的数据都是热点数据&#xff1f; 1.Redis 过期删除策略 1&#xff09;惰性删除:放任键过期不管&#xff0c;但是每次从键空间中获取键时&#xff0c;都检查取得的键是否过期&#xff0c…

FMEA与智能机器人:提升机器人可靠性与安全性的关键

随着科技的飞速发展&#xff0c;智能机器人已经深入到我们生活的方方面面&#xff0c;从工业生产到家庭服务&#xff0c;从深海探险到太空探索&#xff0c;处处都有它们的身影。然而&#xff0c;随着应用的日益广泛&#xff0c;机器人系统的复杂性和不确定性也在增加&#xff0…

学习笔记——C语言基本概念函数——(9)

今天开始函数的学习 目录 1、函数的基本概念 1.1函数的意义 1.2函数的分类 2自定义函数 2.1自定义函数的整个过程 函数定义 函数声明 函数调用 实参 形参和实参的关系 2.2函数传参 地址传递 2.3static的使用 1、函数的基本概念 1.1函数的意义 概念&#xff1a;一…

自定义协议 ,序列化和反序列化

目录 ​编辑 一&#xff0c;问题引入&#xff1a; 二&#xff0c;协议 三&#xff0c;自定义协议 1&#xff0c;协议 2, 序列化和反序列化 四&#xff0c;网络版本的计算器 1&#xff0c;协议的定制 2&#xff0c;计算逻辑 3&#xff0c;服务端 4&#xff0c;客户端 …

基于Spring Boot 3 + Spring Security6 + JWT + Redis实现接口资源鉴权

紧接上一篇文章&#xff0c;基于Spring Boot 3 Spring Security6 JWT Redis实现接口资源鉴权 系列文章指路&#x1f449; 系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类 项目源码&#x1f449; /shijizhe/boot-test 文章目录 1. 修改 UserDetailsServic…

U盘文件突然消失:原因分析与恢复策略

U盘遭遇“幽灵”之手&#xff0c;文件不翼而飞 你是否曾遭遇过这样的诡异情况&#xff1a;前一天还好好存放在U盘里的文件&#xff0c;第二天却突然消失得无影无踪&#xff1f;这简直就像是一场无声的灾难&#xff0c;令人措手不及。U盘作为我们日常工作和生活中不可或缺的数据…

算法系列之数组里的双指针

文章目录 算法系列之数组里的双指针快慢指针代替双重循环暴力解法快慢指针法 用双指针来排序暴力解法双指针排序 算法系列之数组里的双指针 在数组和链表的算法中双指针常出现&#xff0c;这篇用两道题来看一下双指针在数组算法里的用处。 快慢指针代替双重循环 https://lee…

嵌入式3-29

今日作业&#xff1a;用fwrite 和 fseek功能&#xff0c;将一张bmp格式的图片更改成 德国国旗#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> typedef unsigned char bgr[3]; int main(int argc, const char *argv[])…

安装docker 并搭建出一颗爱心树

1、docker介绍 Docker 是⼀个开源的容器运⾏时软件&#xff08;容器运⾏时是负责运⾏容器的软件&#xff09;&#xff0c;基于 Go 语 ⾔编写&#xff0c;并遵从 Apache2.0 协议开源。 Docker可以让开发者打包⾃⼰的应⽤以及依赖到⼀个轻量的容器中&#xff0c;然后发布到任何…

开源大数据集群部署(十九)Hbase部署

作者&#xff1a;櫰木 1 HBASE 安装部署 hbase组件部署主机HMasterhd1.dtstack.com,hd2.dtstack.comHRegionServerhd3.dtstack.com,hd2.dtstack.com,hd1.dtstack.com 2 创建hbase Kerberos主体 在每台机器上进行生成 bash /data/kerberos/getkeytabs.sh /etc/security/key…