鸿蒙应用开发 自定义下拉刷新动画

1 概述

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

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

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

属性动画的使用方式也非常简单,只需要给组件(包括基础组件和容器组件)添加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的参数如下:

属性名称属性类型默认值描述
durationnumber1000动画时长,单位为毫秒,默认时长为1000毫秒。
temponumber1.0动画的播放速度,值越大动画播放越快,值越小播放越慢,为0时无动画效果。
curveCurveCurve.Linear动画变化曲线,默认曲线为线性。
delaynumber0延时播放时间,单位为毫秒,默认不延时播放。
iterationsnumber1播放次数,默认一次,设置为-1时表示无限次播放。
playModePlayModePlayMode.Normal设置动画播放模式,默认播放完成后重头开始播放。
onFinishfunction-动画播放结束时回调该函数。

其中变化曲线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 主要介绍组件动画 animation 属性设置。当组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。

相关概念
  • 属性动画:组件的某些通用属性变化时,可以通过属性动画实现渐变效果,提升用户体验。支持的属性包括 width、height、backgroundColor、opacity、scale、rotate、translate 等。案例中自定义头部组件的属性动画设置主要涉及 duration(动画时长)、tempo(动画速率)、delay(动画延时)、curve(动画曲线)、palyMode(动画模式)和 iterations(动画播放次数)。
使用说明
  1. 首次进入应用默认刷新加载一次数据。
  2. 手指拉拽应用中部可刷新区域,刷新头部跟随手指拖拽显示/隐藏,动画未启动。
  3. 松开手指停止拖拽,如果头部刷新组件未超出可刷新距离,自动回弹隐藏,或者头部刷新组件超出可刷新距离,动画启动,回弹至头部刷新组件完全显示距离,6s 后刷新头部组件回弹隐藏。
约束与限制
  1. 本示例仅支持标准系统上运行,支持设备:华为手机或运行在 DevEco Studio 上的华为手机设备模拟器。
  2. 本示例为 Stage 模型,支持 API version 9。
  3. 本示例需要使用 DevEco Studio 3.1 Release 版本进行编译运行。
源码地址

在公众号「Android指南」后台回复关键字「下拉动画」即可获取。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于 Webpack 插件体系的 Mock 服务

背景 在软件研发流程中,对于前后端分离的架构体系而言,为了能够更快速、高效的实现功能的开发,研发团队通常来说会在产品原型阶段对前后端联调的数据接口进行结构设计及约定,进而可以分别同步进行对应功能的实现,提升研…

LINUX系统安装和管理

目录 一.应用程序 对比应用程序与系统命令的关系 典型应用程序的目录结构 常见的软件包装类型 二.RPM软件包管理 1.RPM是什么? 2.RPM命令的格式 查看已安装的软件包格式 查看未安装的软件包 3.RPM安装包从哪里来? 4.挂载的定义 挂载命令moun…

C语言蛇形矩阵

文章目录 每日一言题目解题思路全部代码结语 每日一言 山有榛,隰有苓。云谁之思?西方美人。 --邶风简兮 题目 解题思路 话不多说,直接看图 通过观察图表,我想到了这种方法: 我将数字放置的位置分为两大类&#xff…

Python深度学习028:神经网络模型太多,傻傻分不清?

文章目录 深度学习网络模型常见CNN网络深度学习网络模型 在深度学习领域,有许多常见的网络模型,每种模型都有其特定的应用和优势。以下是一些广泛使用的深度学习模型: 卷积神经网络(CNN): 应用:主要用于图像处理,如图像分类、物体检测。 特点:利用卷积层来提取图像特…

【UML】第12篇 序列图(1/2)——基本概念和构成

目录 一、什么是序列图(Sequence Diagram) 1.1 定义 1.2 主要用途 1.3 序列图和BPMN的区别和联系 二、序列图的构成 2.1 对象 2.2 生命线 2.3 消息 2.4 激活 序列图,是我个人认为的用处最多的一种图。产品和研发的同学,都…

WorkPlus一站式协同解决方案,助力企业降本增效

在企业数字化转型的过程中,很多企业都会遇到一个共同问题:重复建设基础功能,耗费大量时间和资源。为解决这一难题,WorkPlus已经将一些通用、基础且有技术门槛的功能进行了集成与开发,如IM(即时通讯&#xf…

截断整型提升算数转换

文章目录 🚀前言🚀截断🚀整型提升✈️整型提升是怎样的 🚀算术转换 🚀前言 大家好啊!这里阿辉补一下前面操作符遗漏的地方——截断、整型提升和算数转换 看这一篇要先会前面阿辉讲的数据的存储否则可能看不…

“C语言“——scanf()、getchar() 、putchar()、之间的关系

scanf函数说明 scanf函数是对来自于标准输入流的输入数据作格式转换,并将转换结果保存至format后面的实参所指向的对象。 而const char*format 指向的字符串为格式控制字符串,它指定了可输入的字符串以及赋值时转换方法。 简单来说给一个打印格式(输入…

css radial-gradient 径向渐变基本语法与使用

在之前的文章《深入理解Css linear-gradient线性渐变》我们了解了CSS中的线性渐变,本文将介绍CSS中的另一种渐变———径向渐变(Radial Gradient): CSS中的径向渐变(Radial Gradient)允许你创建从一个颜色…

基于Java SSM框架实现交通事故档案管理系统项目【项目源码+论文说明】

基于java的SSM框架实现交通事故档案管理系统演示 摘要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于交通事故档案管理系统当然也不能排除在外,随着网络技术的不断成熟&#xff0…

企业知识库:从信息管理到知识创新的转变

在当今这个信息爆炸的时代,企业知识库的建设已经成为了企业持续发展的重要基石。从传统的信息管理到现代的知识创新,企业知识库的角色和功能也在不断地演变和升级。本文将探讨企业知识库的发展历程,以及如何实现从信息管理到知识创新的转变。…

谷歌Gemini演示视频解析

在刚刚过去的前两天 谷歌发布了号称最强的多模态大模型Gemini 不仅提供了Ultra、Pro 和 Nano版本 而且在32项学术基准中 Gemini Ultra都达到了SOTA水平 甚至在MMLU测试中 Gemini Ultra 的得分率高达 90.0%, 是第一个超过人类专家的模型 应该说,G…

【vtkWidgetRepresentation】第十八期 vtkHoverWidget

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享vtkHoverWidget,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. vtkHoverWidget vtkHoverWidget用于在呈现窗口中…

如何在飞书自建项目中接入ChatGPT打造智能问答助手并远程访问

文章目录 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 前言 在飞书中创建chatGPT机器人并且对话,在下面操作步骤中…

10.3 uinput

uinput 简介 uinput 是一个内核驱动,应用程序通过它可以在内核中模拟一个输入设备,其设备文件名是 /dev/uinput 或 /dev/input/uinput。 uinput 使用 使用 uinput 时遵循以下步骤: 通过 open 打开 uinput 设备通过 ioctl 设置属性位图通过…

Windows基础知识:一站式整理指南

目录 学习目标: 学习内容: 学习产出: Windows操作系统的发展历史和版本特点 Windows界面和桌面元素的基本介绍 文件和文件夹管理:创建、复制、移动、删除等操作 系统设置和个性化:调整屏幕分辨率、更改桌面背景、设置…

Python之classmethod和staticmethod的区别

python中3种方式定义类方法,常规方式、classmethod修饰方式、staticmethod修饰方式。 class A(object):def foo(self, x):print(调用foo函数 (%s, %s)%(self, x))print(self:, self)classmethoddef class_foo(cls, x):print(调用class_foo函数 (%s, %s) % (cls, x))…

Azure Machine Learning - 如何使用 GPT-4 Turbo with Vision

介绍如何在Azure中使用GPT-4 Turbo with Vision 关注TechLead,分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理…

Plantuml之对象图语法介绍(十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

MySQL undo日志精讲3-从回滚段中申请 Undo 页面链表

回滚段-Rollback Segment Header 页面 回滚段的概念 我们现在知道一个事务在执行过程中最多可以分配4个 Undo 页面链表,在同一时刻不同事务拥有的 Undo 页面链表是不一样的,所以在同一时刻系统里其实可以有许许多多个 Undo 页面链表存在。为了更好的管…