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

相关文章

Java中的ConcurrentBitSet使用小结

《Java中的ConcurrentBitSet使用小结》本文主要介绍了Java中的ConcurrentBitSet使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、核心澄清:Java标准库无内置ConcurrentBitSet二、推荐方案:Eclipse

Go语言结构体标签(Tag)的使用小结

《Go语言结构体标签(Tag)的使用小结》结构体标签Tag是Go语言中附加在结构体字段后的元数据字符串,用于提供额外的属性信息,这些信息可以通过反射在运行时读取和解析,下面就来详细的介绍一下Tag的使... 目录什么是结构体标签?基本语法常见的标签用途1.jsON 序列化/反序列化(最常用)2.数据库操作(

Java中ScopeValue的使用小结

《Java中ScopeValue的使用小结》Java21引入的ScopedValue是一种作用域内共享不可变数据的预览API,本文就来详细介绍一下Java中ScopeValue的使用小结,感兴趣的可以... 目录一、Java ScopedValue(作用域值)详解1. 定义与背景2. 核心特性3. 使用方法

spring中Interceptor的使用小结

《spring中Interceptor的使用小结》SpringInterceptor是SpringMVC提供的一种机制,用于在请求处理的不同阶段插入自定义逻辑,通过实现HandlerIntercept... 目录一、Interceptor 的核心概念二、Interceptor 的创建与配置三、拦截器的执行顺

利用c++判断水仙花数并输出示例代码

《利用c++判断水仙花数并输出示例代码》水仙花数是指一个三位数,其各位数字的立方和恰好等于该数本身,:本文主要介绍利用c++判断水仙花数并输出的相关资料,文中通过代码介绍的非常详细,需要的朋友可以... 以下是使用C++实现的相同逻辑代码:#include <IOStream>#include <vec

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

Java中Map的五种遍历方式实现与对比

《Java中Map的五种遍历方式实现与对比》其实Map遍历藏着多种玩法,有的优雅简洁,有的性能拉满,今天咱们盘一盘这些进阶偏基础的遍历方式,告别重复又臃肿的代码,感兴趣的小伙伴可以了解下... 目录一、先搞懂:Map遍历的核心目标二、几种遍历方式的对比1. 传统EntrySet遍历(最通用)2. Lambd

SQL Server 中的表进行行转列场景示例

《SQLServer中的表进行行转列场景示例》本文详细介绍了SQLServer行转列(Pivot)的三种常用写法,包括固定列名、条件聚合和动态列名,文章还提供了实际示例、动态列数处理、性能优化建议... 目录一、常见场景示例二、写法 1:PIVOT(固定列名)三、写法 2:条件聚合(CASE WHEN)四、

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

C#中checked关键字的使用小结

《C#中checked关键字的使用小结》本文主要介绍了C#中checked关键字的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录✅ 为什么需要checked? 问题:整数溢出是“静默China编程”的(默认)checked的三种用