OpenHarmony实战开发-动画曲线、如何实现动画衔接

news/2024/9/25 17:16:00/

UI界面除了运行动画之外,还承载着与用户进行实时交互的功能。当用户行为根据意图变化发生改变时,UI界面应做到即时响应。例如用户在应用启动过程中,上滑退出,那么启动动画应该立即过渡到退出动画,而不应该等启动动画完成后再退出,从而减少用户等待时间。对于桌面翻页类从跟手到离手触发动画的场景,离手后动画的初始速度应承继手势速度,避免由于速度不接续导致停顿感的产生。针对以上场景,系统已提供动画与动画、手势与动画之间的衔接能力,保证各类场景下动画平稳光滑地过渡的同时,尽可能降低开发难度。

假设对于某一可动画属性,存在正在运行的动画。当UI侧行为改变该属性终点值时,开发者仅需在animateTo动画闭包中改变属性值或者改变animation接口作用的属性值,即可产生动画。系统会自动衔接之前的动画和当前的动画,开发者仅需要关注当前单次动画的实现。

import curves from '@ohos.curves'
class SetSlt{scaleToggle:boolean = trueset():void{this.scaleToggle = !this.scaleToggle;}
}
let CurAn:Record<string,curves> = {'curve':curves.springMotion()}
// 第一步:声明相关状态变量
@state scaleToggle: boolean = true;...
Column() {Button()// 第二步:将状态变量设置到相关可动画属性接口.scale(this.scaleToggle ? 1 : 0.5)// 第三步:通过点击事件改变状态变量值,影响可动画属性值.onclick(() => {let sets = new SetSlt()sets.set()})// 第四步:通过隐式动画接口开启隐式动画,动画终点值改变时,系统自动添加衔接动画.animation(CurAn)
}
...

完整示例如下。通过点击click,红色方块的缩放属性会发生变化。当连续快速点击click时,缩放属性的终点值连续发生变化,当前动画也会平滑过渡到朝着新的缩放属性终点值运动。

import curves from '@ohos.curves';
class SetSlt{isAnimation:boolean = trueset():void{this.isAnimation = !this.isAnimation;}
}
@Entry
@Component
struct AnimationToAnimationDemo {@State SetAnimation: SetSlt = new SetSlt();build() {Column() {Text('ArkUI').fontWeight(FontWeight.Bold).fontSize(12).fontColor(Color.White).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xf56c6c).width(100).height(100).scale({ x: this.SetAnimation.isAnimation ? 2 : 1, y: this.SetAnimation.isAnimation ? 2 : 1 }).animation({ curve: curves.springMotion(0.4, 0.8) })Button('Click').margin({ top: 200 }).onClick(() => {this.SetAnimation.set()})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}
}

在这里插入图片描述

手势与动画的衔接

使用滑动、捏合、旋转等手势的场景中,跟手过程中一般会触发属性的改变。离手后,这部分属性往往会继续发生变化,直到到达属性终点值。

离手阶段的属性变化初始速度应与离手前一刻的属性改变速度保持一致。如果离手后属性变化速度从0开始,就好像正在运行的汽车紧急刹车,造成观感上的骤变是用户和开发者都不希望看到的。

针对在手势和动画之间进行衔接的场景(如列表滑动),可以在跟手阶段每一次更改组件属性时,都做成使用跟手弹簧曲线的属性动画。离手时再用离手弹簧曲线产生离手阶段的属性动画。对于采用springMotion曲线的动画,离手阶段动画将自动继承跟手阶段动画的速度,并以跟手动画当前位置为起点,运动到指定的属性终点。

import curves from '@ohos.curves'
class SetOffset{offsetX:number = 0;offsetY:number = 0;set(x:number,y:number):void{this.offsetX = x;this.offsetY = y;}
}
// 第一步:声明相关状态变量
@state offsetX: number = 0;
@State offsetY: number = 0;
targetOffsetX: number = 100;
targetOffsetY: number = 100;
...
Column() // 第二步:将状态变量设置到相关可动画属性接口.translate({ x: this.offsetX, y: this.offsetY}).gesture(PanGesture({}).onActionUpdate((event?: GestureEvent) => {// 第三步:在跟手过程改变状态变量值,并且采用reponsiveSpringMotion动画运动到新的值animateTo({curve: curves.responsiveSpringMotion()}, () => {if(event){let setxy = new SetOffset();setxy.set(event.offsetX,event.offsetY)}})}).onActionEnd(() => {// 第四步:在离手过程设定状态变量终点值,并且用springMotion动画运动到新的值,springMotion动画将继承跟手阶段的动画速度animateTo({curve: curves.SpringMotion()}, () => {let setxy = new SetOffset();setxy.set(targetOffsetX,targetOffsetY)})}))
...

完整的示例和效果如下。

import curves from '@ohos.curves';@Entry
@Component
struct SpringMotionDemo {@State positionX: number = 100;@State positionY: number = 100;diameter: number = 50;build() {Column() {Row() {Circle({ width: this.diameter, height: this.diameter }).fill(Color.Blue).position({ x: this.positionX, y: this.positionY }).onTouch((event?: TouchEvent) => {if(event){if (event.type === TouchType.Move) {// 跟手过程,使用responsiveSpringMotion曲线animateTo({ curve: curves.responsiveSpringMotion() }, () => {// 减去半径,以使球的中心运动到手指位置this.positionX = event.touches[0].windowX - this.diameter / 2;this.positionY = event.touches[0].windowY - this.diameter / 2;console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);})} else if (event.type === TouchType.Up) {// 离手时,使用springMotion曲线animateTo({ curve: curves.springMotion() }, () => {this.positionX = 100;this.positionY = 100;console.info(`touchUp, animateTo x:100, y:100`);})}}})}.width("100%").height("80%").clip(true) // 如果球超出父组件范围,使球不可见.backgroundColor(Color.Orange)Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {Text("拖动小球").fontSize(16)}.width("100%")Row() {Text('点击位置: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)}.padding(10).width("100%")}.height('100%').width('100%')}
}

在这里插入图片描述

如果大家还没有掌握鸿蒙,现在想要在最短的时间里吃透它,我这边特意整理了《鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程》以及《鸿蒙开发>鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

OpenHarmony APP开发教程步骤:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

鸿蒙开发>鸿蒙开发学习手册》:

如何快速入门:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

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

在这里插入图片描述

开发基础知识:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

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

在这里插入图片描述

基于ArkTS 开发:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

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

在这里插入图片描述

鸿蒙生态应用开发白皮书V2.0PDF:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述


http://www.ppmy.cn/news/1454696.html

相关文章

Redis Cluster集群方案什么情况下会导致整个集群不可用?

Redis 没有使用哈希一致性算法&#xff0c;而是使用哈希槽。 Redis 中的哈希槽一共有16384个&#xff0c;计算给定 密钥的哈希槽&#xff0c;我们只需要对密钥的 CRC16 去取 16384。假设集群中有A、B、C三个集群节点&#xff0c; 不存在复制模式下&#xff0c;每个集群的节点包…

Edge扩展应用程序的上架流程

前言 在软件开发的生命周期中&#xff0c;发布流程是将产品推向市场并交付给用户的关键阶段。它不仅标志着一个项目从开发阶段到用户手中的转变&#xff0c;也是确保软件质量和用户体验的重要环节。那么一个清晰、高效且可重复的发布流程对于任何软件项目的成功至关重要&#…

pandas学习笔记13

map,apply,applymap ** apply&#xff1a;应用在DataFrame的行或列中&#xff1b; applymap&#xff1a;应用在DataFrame的每个元素中&#xff1b; map&#xff1a;应用在单独一列&#xff08;Series&#xff09;的每个元素中。** apply()方法 前面也说了apply方法是一般性的…

基于Linux C++多线程服务器 + Qt上位机开发 + STM32 + 8266WIFI的智慧无人超市

前言 针对传统超市购物车结账排队时间长、付款效率低的问题&#xff0c;提出了一种更符合现代社会人们购物方式-基于RFID的自助收银系统。习惯了快节奏生活的人们都会选择自助收银机结账&#xff0c;理由显而易见&#xff1a;自助收银机结账很方便&#xff0c;几乎不用排队&am…

论文阅读_使用有向无环图实现流程工程_AgentKit

英文名称: AgentKit: Flow Engineering with Graphs, not Coding 中文名称: AgentKit&#xff1a;使用图而非编码进行流程工程 链接: https://arxiv.org/pdf/2404.11483.pdf 代码: https://github.com/holmeswww/AgentKit 作者: Yue Wu, Yewen Fan, So Yeon Min, Shrimai Prabh…

Python中的`next()`函数:深入解析与应用

引言 在Python编程中&#xff0c;迭代是处理数据集合的基础操作。我们熟悉使用for循环和while循环来进行迭代&#xff0c;但你是否知道Python中还提供了一个名为next()的内建函数&#xff0c;它可以用来迭代数据流中的元素&#xff1f;本文将带你深入了解next()函数的工作原理…

偏微分方程算法之迭代法(番外篇)

目录 一、概念介绍 1、Jacobi迭代 2、Gauss-Seidel迭代 3、SOR迭代 二、常用方法及理论推导 1、 Jacobi迭代 2、Gauss-Seidel迭代 3、SOR迭代 三、椭圆型方程五点菱形差分迭代格式 1、 Jacobi迭代 2、Gauss-Seidel迭代 3、SOR迭代 一、概念介绍 三种迭代方法都是用…

NVME第二章 system Bus Registers

本章节主要详细地介绍如何为Nvme控制器构造PCI Header&#xff0c;PCI Capability&#xff0c;PCI Express Extended Capabilities。&#xff08;PCI相关可参考博客&#xff09; 2.1 PCI Header 1 PCI枚举过程 根据NVMe驱动过程&#xff0c;在PCI总线枚举设备时&#xff0c;需…