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

2024-03-30 06:28

本文主要是介绍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)开发学习手册

这篇关于OpenHarmony动效示例-如何使用animateTo实现显式动画。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860721

相关文章

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹