首页 > 其他分享 >给应用添加动画

给应用添加动画

时间:2024-01-21 21:47:26浏览次数:26  
标签:动画 state 添加 应用 刷新 组件 播放 属性

属性动画的使用  

概述

属性动画,是最为基础的动画,其功能强大、使用场景多,应用范围较广。常用于如下场景中:

  • 一、页面布局发生变化。例如添加、删除部分组件元素。
  • 二、页面元素的可见性和位置发生变化。例如显示或者隐藏部分元素,或者将部分元素从一端移动到另外一端。
  • 三、页面中图形图片元素动起来。例如使页面中的静态图片动起来。

简单来说,属性动画是组件的通用属性发生改变时而产生的属性渐变效果。如下图所示,其原理是,当组件的通用属性发生改变时,组件状态由初始状态逐渐变为结束状态的过程中,会创建多个连续的中间状态,逐帧播放后,就会形成属性渐变效果,从而形成动画。

属性动画的使用方式也非常简单,只需要给组件(包括基础组件和容器组件)添加animation属性,并设置好参数,如下代码所示:

Image($r('app.media.image1'))   
   .animation({   
      duration: 1000,    
      tempo: 1.0,    
      delay: 0,    
      curve: Curve.Linear,    
      playMode: PlayMode.Normal,    
      iterations: 1  
   })

2 创建属性动画页面

如下图所示,在该下拉刷新动画场景中,一共有6个属性动画。头部中的五个图标的移动放大动画中,每个图标都是单独的一个动画,其共同组合成一个刷新等待动画。最后是下方组件上移的一个移动动画。为方便理解,图中下方的内容将以图片来代替实际应用的功能页面。

图2-1 :示例动画

该6个属性动画创建方式类似,以五个图标放大移动动画的为例来讲解如何创建属性动画。

首先,创建一个头部刷新组件RefreshAnimHeader,在其中自定义一个图标组件AttrAnimIcons,用Image组件将资源图标引入,并设置好样式,如下所示:

@Component
export default struct RefreshAnimHeader {
  ...
  @Builder AttrAnimIcons(iconItem) {  
    Image(iconItem.imgRes)    
      .width(this.iconWidth)    
      .position({ x: iconItem.posX })    
      .objectFit(ImageFit.Contain)    
      .animation({      
        duration: 2000,      
        tempo: 3.0,      
        delay: iconItem.delay,      
        curve: Curve.Linear,      
        playMode: PlayMode.Alternate,      
        iterations: -1
     })
  }
  ...
}

然后在build方法中使用Row容器组件,将自定义的图标组件引入,并设置好样式,同时定义组件状态iconWidth,添加onApper事件,修改iconWidth的值,使其从30变为100,触发UI状态更新。

@Component
export default struct RefreshAnimHeader {
  ...
  @State iconWidth: number = 30;
  private onStateCheck() {  
    if (this.state === RefreshState.REFRESHING) {    
      this.iconWidth = 100;  
    } else {    
      this.iconWidth = 30;  
    }
  }
  build() {  
    Row() {    
      ForEach(CommonConstants.REFRESH_HEADER_FEATURE, (iconItem) => {     
        this.AttrAnimIcons(iconItem)    
      }, item => item.toString())  
    }  
     .width("100%")  
     .height("100%")  
     .onAppear(() => {    
       this.onStateCheck();
     })
  }
}

运行代码,即可看到五个图标的移动放大动画效果。

1、animation属性作用域。animation自身也是组件的一个属性,其作用域为animation之前。即产生属性动画的属性须在animation之前声明,其后声明的将不会产生属性动画。以示例中的五个图标动画为例,我们期望产生动画的属性为Image组件的width属性,故该属性width需在animation属性之前声明。如果将该属性width在animation之后声明,则不会产生动画效果。

2、产生属性动画的属性变化时需触发UI状态更新。在本示例中,产生动画的属性width,其值是通过变量iconWidth从30变为100,故该变量iconWidth的改变需触发UI状态更新。

3、产生属性动画的属性本身需满足一定的要求,并非任何属性都可以产生属性动画。目前支持的属性包括width、height、position、opacity、backgroundColor、scale、rotate、translate等

3 属性动画参数调整

属性动画中animation的参数如下:

属性名称

属性类型

默认值

描述

duration

number

1000

动画时长,单位为毫秒,默认时长为1000毫秒。

tempo

number

1.0

动画的播放速度,值越大动画播放越快,值越小播放越慢,为0时无动画效果。

curve

Curve

Curve.Linear

动画变化曲线,默认曲线为线性。

delay

number

0

延时播放时间,单位为毫秒,默认不延时播放。

iterations

number

1

播放次数,默认一次,设置为-1时表示无限次播放。

playMode

PlayMode

PlayMode.Normal

设置动画播放模式,默认播放完成后重头开始播放。

onFinish

function

-

动画播放结束时回调该函数。

其中变化曲线curve枚举值为:

名称

描述

Linear

表示动画从头到尾的速度都是相同的。

Ease

表示动画以低速开始,然后加快,在结束前变慢,CubicBezier(0.25, 0.1, 0.25, 1.0)。

EaseIn

表示动画以低速开始,CubicBezier(0.42, 0.0, 1.0, 1.0)。

EaseOut

表示动画以低速结束,CubicBezier(0.0, 0.0, 0.58, 1.0)。

EaseInOut

表示动画以低速开始和结束,CubicBezier(0.42, 0.0, 0.58, 1.0)。

FastOutSlowIn

标准曲线,cubic-bezier(0.4, 0.0, 0.2, 1.0)。

LinearOutSlowIn

减速曲线,cubic-bezier(0.0, 0.0, 0.2, 1.0)。

FastOutLinearIn

加速曲线,cubic-bezier(0.4, 0.0, 1.0, 1.0)。

ExtremeDeceleration

急缓曲线,cubic-bezier(0.0, 0.0, 0.0, 1.0)。

Sharp

锐利曲线,cubic-bezier(0.33, 0.0, 0.67, 1.0)。

Rhythm

节奏曲线,cubic-bezier(0.7, 0.0, 0.2, 1.0)。

Smooth

平滑曲线,cubic-bezier(0.4, 0.0, 0.4, 1.0)。

Friction

阻尼曲线,CubicBezier(0.2, 0.0, 0.2, 1.0)。

播放模式playMode枚举值为:

名称

描述

Normal

动画按正常播放。

Reverse

动画反向播放。

Alternate

动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放。

AlternateReverse

动画在奇数次(1、3、5...)反向播放,在偶数次(2、4、6...)正向播放。

本文以参数delay和onFinish为例来演示和讲解属性动画的参数调整。其他参数的效果可自行尝试。

延时播放时间delay的设置

在单个的组件元素的属性动画中,一般不设置参数delay的值。而在需要设置时,往往是需要在动画开始前做一些准备工作,具体依场景而定,本文在此不讨论。

在由多个组件元素的属性动画组合的动画中,例如示例动画中的五个图标的属性动画组合而成的刷新等待动画,通过设置参数delay的值,可以使各个组件元素之间按照一定的秩序依次播放,形成跌宕起伏、鳞次栉比的动画效果。在此场景中,该值的大小又与duration相关联。

该如何设置各个图标的参数delay的值呢?

在设置delay值之前,我们先理解一个概念:延时间距。其意思是两个图标组件的延时参数delay的差值,即:delay2-delay1=延时间距。要想实现五个图标之间以良好的秩序先后移动放大,各个图标之间的延时间距是一样的,例如延时间距为100ms时,此五个图标的延时delay可以分别设置为100ms、200ms、300ms、400ms、500ms。

在实际开发场景中,我们该如何确定延时间距呢?

在此有个经验可以参考:在延时间距不超过动画时长duration时,总延时间距越接近duration,秩序性越好。其中,总延时间距为延时间距与图标数量的乘积,即:延时间距*图标数量=总延时间距。

故此,我们在设置参数delay时,需要确定动画时长duration的值。该值默认为1000ms,具体时长可依据具体的业务需要来决定。

在本示例动画中,图标动画时长duration为2000ms,故延时间距为2000ms/5=400ms,五个图标的延时参数delay可分别设置为400ms、800ms、1200ms、1600ms、2000ms。其效果如示例图所示,图标先后秩序明显,视觉效果良好。

onFinish回调函数的使用

参数onFinish与参数iterations有关。当参数iterations播放结束时,会调用onFinish函数来进行后续的业务处理。例如提示动画播放结束。

Image(iconItem.imgRes)
  .width(this.iconWidth)
  .position({ x: iconItem.posX })
  .objectFit(ImageFit.Contain)
  .animation({
    duration: 2000,
    tempo: 3.0,
    delay: iconItem.delay,
    curve: Curve.Linear,
    playMode: PlayMode.Normal,
    iterations: 1,
    onFinish: () => {      
      prompt.showToast({ message:"动画播放结束!!!" })
    }
  })

当iterations设置为-1时,表示无限次播放,则onFinish回调函数不会被调用。

4 关闭属性动画页面

此处需要将关闭属性动画区别开来:

  • 属性动画关闭,是指动画播放结束,但是动画组件依然存在并显示在页面上。
  • 关闭属性动画页面,是指将动画的组件删除或者隐藏起来。

在本示例动画中,指将头部刷新组件RefreshAnimHeader隐藏起来。该如何实现呢?

首先,在组件RefreshAnimHeader中添加变量state,并用@Consume监听其值的变化,同时添加条件渲染逻辑,根据state的值来判断是否需要关闭。当state变为IDLE状态时,表示需要关闭属性动画页面。

@Component
export default struct RefreshAnimHeader {  
  @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateCheck') state: RefreshState;
  build() {
    Row() {
      if (this.state !== RefreshState.IDLE) { // start or stop animation when idle state.
        ForEach(CommonConstants.REFRESH_HEADER_FEATURE, (iconItem) => {
          this.AttrAnimIcons(iconItem)
        }, item => item.toString()}
      }
    }
    .width(CommonConstants.FULL_LENGTH)
    .height(CommonConstants.FULL_LENGTH)
    .onAppear(() => {
      this.onStateCheck();
    })
  }
}

其次,在本示例中,通过下方图片的上移属性动画来关闭刷新组件RefreshAnimHeader。在组件RefreshComponent中,通过@Consume与组件RefreshAnimHeader的@Consume进行间接绑定,修改state变量的值为IDLE状态即可关闭属性动画页面。

@Component
export default struct RefreshComponent {
  @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateChanged') state: RefreshState;
  build() {
    List({ scroller: this.listController }) {
      ListItem() {
         ...
      }
  }  
  .animation({
    curve: Curve.Smooth,
    duration: RefreshConstants.REFRESH_HEADER_ANIM_DURATION,
    playMode: PlayMode.Normal,
    onFinish: () => {
      if (this.headerOffset === -RefreshConstants.REFRESH_HEADER_HEIGHT) {
        this.state = RefreshState.IDLE;
      }
    }
  })
}

5 参考

具体代码信息请参考Codelab:自定义下拉刷新动画(ArkTS)

案例:自定义下拉刷新动画(ArkTS)

 

介绍

本篇Codelab主要介绍组件动画animation属性设置。当组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。

本Codelab使用的display接口处于mock阶段,在预览器上使用会显示白屏现象,可选择在真机或模拟器上运行。

相关概念

  • 属性动画:组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。案例中自定义头部组件的属性动画设置主要涉及duration(动画时长)、tempo(动画速率)、delay(动画延时)、curve(动画曲线)、palyMode(动画模式)和iterations(动画播放次数)。

完整示例

gitee源码地址

源码下载   自定义下拉刷新动画(ArkTS).zip   环境搭建

我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。

软件要求

硬件要求

  • 设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
  • HarmonyOS系统:3.1.0 Developer Release。

环境搭建

  1. 安装DevEco Studio,详情请参考下载和安装软件
  2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
    • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
    • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境
  3. 开发者可以参考以下链接,完成设备调试的相关配置:
  代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。

    No Preview
  1. ├──entry/src/main/ets // 代码区
  2. │ ├──common
  3. │ │ ├──constants
  4. │ │ │ ├──CommonConstants.ets // 公共常量类
  5. │ │ │ └──RefreshConstants.ets // 下拉刷新常量类
  6. │ │ └──utils
  7. │ │ ├──DimensionUtil.ets // 屏幕适配工具类
  8. │ │ └──GlobalContext.ets // 全局上下文工具类
  9. │ ├──entryability
  10. │ │ └──EntryAbility.ets // 程序入口类
  11. │ ├──pages
  12. │ │ ├──FileManagerIndex.ets // 文件管理Tab页
  13. │ │ └──TabIndex.ets // Tab管理页
  14. │ ├──view
  15. │ │ ├──RefreshAnimHeader.ets // 动画刷新组件
  16. │ │ ├──RefreshComponent.ets // 下拉刷新组件
  17. │ │ └──RefreshDefaultHeader.ets // 默认刷新组件
  18. │ └──viewmodel
  19. │ ├──AnimationModel.ets // 动画封装类
  20. │ └──CardModel.ets // 页签封装类
  21. └──entry/src/main/resources // 资源文件目录
自定义下拉组件

自定义下拉刷新通过自定义List组件RefreshComponent实现。在List容器中添加自定义刷新头部组件和其它的需要刷新部件,RefreshComponent提供了头部样式设置,刷新部件样式设置和刷新回调方法设置。

  • 头部样式设置。本Codelab提供了DEFAULT默认刷新样式和CLOUD云朵动画刷新样式设置,在RefreshComponent组件初始化时,判断当前刷新样式进行渲染。
  • 刷新部件样式。刷新部件样式itemLayout为嵌入RefreshComponent组件中的元素,通过@BuilderParam装饰符定义,可根据具体业务需求,当前为默认的Image组件样式。
  • 刷新回调方法设置。在手指拖拽刷新头部滑出的过程中计算滑出的距离是否超出可刷新距离,松开手指时如果超出可刷新距离则调用“onRefresh”方法。
    No Preview
  1. // RefreshComponent.ets
  2. // 设置RefreshComponent刷新组件state状态的更新。
  3. @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateChanged') state: number;
  4. private onStateChanged() {
  5. switch (this.state) {
  6. case RefreshState.REFRESHING:
  7. if (this.onRefresh !== undefined) {
  8. this.onRefresh();
  9. }
  10. break;
  11. ...
  12. }
  13. }
  14. // 监听RefreshComponent中List组件的触摸事件。
  15. List({ scroller: this.listController }) {
  16. ListItem() {
  17. Column() {
  18. ...
  19. }
  20. ...
  21. }
  22. }
  23. ...
  24. .onTouch((event?: TouchEvent) => {
  25. if (!event) {
  26. return;
  27. }
  28. switch (event.type) {
  29. case TouchType.Down:
  30. if (this.state === RefreshState.IDLE) {
  31. this.state = RefreshState.DRAGGING;
  32. }
  33. break;
  34. case TouchType.Move:
  35. if (this.state === RefreshState.DRAGGING
  36. && this.listController.currentOffset().yOffset <= -RefreshConstants.REFRESH_EFFECTIVE_HEIGHT) {
  37. this.state = RefreshState.DRAGGING_REFRESHABLE;
  38. }
  39. break;
  40. case TouchType.Up:
  41. if (this.state === RefreshState.DRAGGING_REFRESHABLE) {
  42. this.headerOffset = 0;
  43. this.state = RefreshState.REFRESHING;
  44. }
  45. break;
  46. default:
  47. break;
  48. }
  49. // FileManagerIndex.ets
  50. //onRefresh事件没有做相关刷新,只做了模拟延时操作,开发者可以自行加入真实网络加载动作。
  51. onRefresh: () => {
  52. setTimeout(() => {
  53. this.state = RefreshState.COMPLETE;
  54. }, CommonConstants.REFRESH_DEFAULT_TIMEOUT);
  55. }
自定义刷新动画

本Codelab中自定义刷新是由5个图片的组合动画效果。

  • 每个Image通过iconItem参数分别设置各自的x轴偏移量和延时播放的属性动画效果。
  • 监听RefreshComponent刷新组件state状态的变化,当前状态为REFRESHING状态时,改变@State修饰的图片宽度变量iconWidth来启动动画。
    No Preview
  1. // RefreshAnimHeader.ets
  2. @Consume(RefreshConstants.REFRESH_STATE_TAG) @Watch('onStateCheck') state: number;
  3. private onStateCheck() {
  4. if (this.state === RefreshState.REFRESHING) {
  5. this.iconWidth = CommonConstants.REFRESH_HEADER_ITEM_SCALE_WIDTH;
  6. } else {
  7. this.iconWidth = CommonConstants.REFRESH_HEADER_ITEM_DEFAULT_WIDTH;
  8. }
  9. }
总结

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

  1. 使用属性动画实现自定义下拉组件。
  2. 使用属性动画实现自定义刷新组件。

 

标签:动画,state,添加,应用,刷新,组件,播放,属性
From: https://www.cnblogs.com/flyingsir/p/17978418

相关文章

  • [Mac软件]App Cleaner & Uninstaller 8.2.6应用程序清理和卸载
    AppCleaner&Uninstaller是一款Mac应用程序,它可以帮助用户完全删除应用程序及其相关的服务文件、扩展文件等。以下是该应用程序的主要功能:完全删除应用程序:通过将应用程序图标拖到垃圾桶中删除程序,可以彻底清除应用程序及其相关文件,释放磁盘空间。删除所有类型的服务文件:除了删除......
  • 二分搜索应用 II
    目录1.题目列表2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目2.1.2.解题思路2.1.3.代码实现1.题目列表序号题目难度1410.分割数组的最大值困难2.应用2.1.Leetcode410.分割数组的最大值2.1.1.题目410.分割数组的最大值给定一个非负整......
  • 如何在实践中应用一体化运维
      一体化运维作为一种先进的运维理念,不仅仅停留在理论层面,更需要在实践中得到应用和验证。以下是在实践中如何应用一体化运维的具体步骤和策略:1. 明确运维目标与需求:在实施一体化运维之前,企业需要明确自身的运维目标和需求。这包括了解现有IT系统的架构、性能瓶颈、安全隐患等......
  • 25new和delete重载实现的对象池应用
    new和delete重载实现的对象池应用在类底层维护一个结构体链表,new和delete重载以避免大量重复的new和delete操作。usingnamespacestd;#include<iostream>staticconstintPOOL_ITEM_SIZE=1000000;template<typenameT>classQueue{public: Queue() { _front=_r......
  • Transformer的应用
    Transformer写在前面本学期学习了NLP的课程,本小菜鸡结合做的课设(基于Transformer的英文文档摘要系统的设计与实现),来写一下有关于Transformer的相关内容吧,有问题之处还请各位大佬批评指正系统的背景抽象文本摘要是自然语言处理中最具挑战性的任务之一,涉及理解长段落、信息压缩......
  • 将 .NET 8应用 以 dotnet publish 创建容器镜像并结合 Github Actions 部署到 Azure
    介绍.NET8无需DockerFile即可为.NET应用创建docker映像的新方法,我将使用dotnetpublish将.NET应用容器化,在本文中,我将分享我如何为.NET8的项目创建一个简单的ci/cd的经验。它包括2个主题:创建用于生成.NET应用并将其发布到Azure的GitHub工作流如何使用do......
  • 认识存储网络:手动搭建 IPFS 环境以及简单应用的开发
    认识存储网络:手动搭建IPFS环境以及简单应用的开发一、实验背景IPFS是一个点对点的分布式文件系统,将所有的计算设备与相同的文件系统连接起来。在某些方面,IPFS类似于Web,但IPFS可以被视为一个单一的比特流群,在Git存储库中交换对象。换句话说,IPFS提供了一个具有内容寻址的超链接......
  • raid级别及应用场景
    最少几块硬盘安全冗余可用容量性能使用场景举例Raid01最低所有硬盘容量的和读写最快不要求安全,只要求速度数据库从库、存储从库Raid1只能有2块100%一半(两块硬盘容量之和)写入速度慢,读取还可以只追求安全性,对速度没要求系统盘、监控服务器Raid5......
  • 软件测试|探索Flask接口路由技术:构建灵活可拓展的Python应用
    测试管理班是专门面向测试与质量管理人员的一门课程,通过提升从业人员的团队管理、项目管理、绩效管理、沟通管理等方面的能力,使测试管理人员可以更好的带领团队、项目以及公司获得更快的成长。提供1v1私教指导,BAT级别的测试管理大咖量身打造职业规划。什么是路由路由是将URL地......
  • sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签
    搭建shiro环境1:导入boot项目中要用到的shiro依赖<!--shiro部分--><!--shiro核心源码--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version......