社区编辑申请
注册/登录
HarmonyOS 属性动画扩展
系统
在日常开发中,我们经常需要基于这个类进行扩展编写,去适应真实场景。因此,通过收集常用的场景,整理出一个属性动画的扩展类ValueAnimator。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

简介

HarmonyOS 提供了AnimatorValue来执行属性动画,但是其方法数很少,并且属性值范围局限于[0,1],也不直接支持动画反转等一些常用的操作。在日常开发中,我们经常需要基于这个类进行扩展编写,去适应真实场景。因此,通过收集常用的场景,整理出一个属性动画的扩展类ValueAnimator。

效果演示

HarmonyOS 属性动画扩展-鸿蒙HarmonyOS技术社区

实现思路

1. 动画分类

实际开发过程,我们大部分的动画都是作用于视图组件。任何复杂的动画,通过逐帧分解,最终都可以归纳为如下几种基础动画的组合:

  • X,Y轴缩放动画
  • X,Y轴平移动画
  • 透明度动画
  • 旋转角度动画
  • 组件宽高尺寸动画

2. 动画操作

对于动画的操作,我们可以归纳出以下这些动作:

  • 开始动画
  • 暂停动画
  • 取消动画
  • 结束动画
  • 反转动画
  • 设置动画起始值
  • 设置动画延时
  • 设置动画执行时长
  • 设置动画插值器
  • 设置动画状态监听
  • 设置动画进度监听
  • 设置动画执行次数
  • 设置动画重复模式
  • 设置组件动画属性值

3. 代码实现

3.1 视图动画的实现

系统原生提供的AnimatorValue为我们提供了[0,1]的动画范围。因此最简单的实现方式是定义一个ValueAnimator,内部包含一个系统的AnimatorValue来计算[0,1]的进度值,通过自己的逻辑转换为我们期望的动画值。

  1. public class ValueAnimator { 
  2.     private AnimatorValue innerAnimator; 
  3.  
  4.     // 监听动画值的变化 
  5.     private final AnimatorValue.ValueUpdateListener valueUpdateListener = new AnimatorValue.ValueUpdateListener() { 
  6.         @Override 
  7.         public void onUpdate(AnimatorValue animatorValue, float fraction) { 
  8.             Object[] takeValues = values
  9.             // 动画反转运算处理 
  10.             if (takeReverseLogic && isReversing) { 
  11.                 takeValues = reverseValues; 
  12.             } 
  13.             Object animatedValue = takeValues[0]; 
  14.             // fraction为[0,1]当前时间的进度,通过计算转换成实际的动画值 
  15.             if (animatedValue != null) { 
  16.                 if (animatedValue instanceof Integer) { 
  17.                     int start = (int) takeValues[0]; 
  18.                     int end = (int) takeValues[1]; 
  19.                     animatedValue = start + (int) (fraction * (end - start)); 
  20.                 } else { 
  21.                     float start = (float) takeValues[0]; 
  22.                     float end = (float) takeValues[1]; 
  23.                     animatedValue = start + fraction * (end - start); 
  24.                 } 
  25.             } 
  26.             currentAnimatedValue = animatedValue; 
  27.             // 将当前进度值通知给外部调用者 
  28.             if (updateListeners != null) { 
  29.                 notifyOuterListener(animatorValue, fraction, animatedValue); 
  30.             } 
  31.             // 如果是组件动画,将动画值转换为视图组件的属性值变化 
  32.             if (targetHolder != null && targetHolder.get() != null) { 
  33.                 updateComponentProperty((Float) animatedValue); 
  34.             } 
  35.         } 
  36.     }; 
  37.  
  38.     // 动画值转换为视图组件的属性变化 
  39.     private void updateComponentProperty(Float currentValue) { 
  40.         Component component = targetHolder.get(); 
  41.         for (Property property : targetProperties) { 
  42.             switch (property) { 
  43.                 case SCALE_X:// 缩放x 
  44.                     component.setScaleX(currentValue); 
  45.                     break; 
  46.                 case SCALE_Y:// 缩放y 
  47.                     component.setScaleY(currentValue); 
  48.                     break; 
  49.                 case TRANSLATION_X:// 平移x 
  50.                     component.setTranslationX(currentValue); 
  51.                     break; 
  52.                 case TRANSLATION_Y:// 平移y 
  53.                     component.setTranslationY(currentValue); 
  54.                     break; 
  55.                 case ALPHA:// 透明度 
  56.                     component.setAlpha(currentValue); 
  57.                     break; 
  58.                 case ROTATION:// 中心旋转 
  59.                     component.setRotation(currentValue); 
  60.                     break; 
  61.                 case WIDTH:// 尺寸宽 
  62.                     float width = currentValue; 
  63.                     component.setWidth((int) width); 
  64.                     break; 
  65.                 case HEIGHT:// 尺寸高 
  66.                     float height = currentValue; 
  67.                     component.setHeight((int) height); 
  68.                     break; 
  69.                 default
  70.                     break; 
  71.             } 
  72.         } 
  73.     } 

3.2 反向循环动画的实现

要执行反向循环动画,我们需要监听循环动画的每次循环节点,然后在下一次动画执行开始把动画的起始值反置。

  1. private static final int MAX_SIZE = 2; 
  2.   private final Object[] values = new Object[MAX_SIZE];// 正向动画起始值 
  3.   private final Object[] reverseValues = new Object[MAX_SIZE];// 反向动画起始值 
  4.  
  5.   // 设置起始值时,除了正向动画起始值,同时构建一份反向起始值 
  6.   public void setFloatValues(float start, float end) { 
  7.       values[0] = start; 
  8.       values[1] = end
  9.       reverseValues[0] = end
  10.       reverseValues[1] = start; 
  11.   } 
  12.  
  13.   // 监听动画循环点 
  14.   private final Animator.LoopedListener loopedListener = new Animator.LoopedListener() { 
  15.       @Override 
  16.       public void onRepeat(Animator animator) { 
  17.           // 如果循环模式设置为反向,下次执行动画则反向执行 
  18.           // 例如当前是[0,1],动画结束后就会从[1,0]开始执行,再下次又从[0,1],如此循环... 
  19.           if (takeReverseLogic) { 
  20.               isReversing = !isReversing; 
  21.           } 
  22.           if (listeners != null) { 
  23.               for (AnimatorListener listener : listeners) { 
  24.                   listener.onAnimationRepeat(ValueAnimator.this); 
  25.               } 
  26.           } 
  27.       } 
  28.   }; 
  29.  
  30.   // 监听动画值的变化 
  31.   private final AnimatorValue.ValueUpdateListener valueUpdateListener = new AnimatorValue.ValueUpdateListener() { 
  32.       @Override 
  33.       public void onUpdate(AnimatorValue animatorValue, float fraction) { 
  34.           Object[] takeValues = values
  35.           if (takeReverseLogic && isReversing) { 
  36.               // 根据循环模式读取正向还是反向起始值 
  37.               takeValues = reverseValues; 
  38.           } 
  39.           ... 
  40.   }; 
  41.  
  42.   // 反向执行动画 
  43.   public void reverse() { 
  44.       takeReverseLogic = !takeReverseLogic; 
  45.       isReversing = !isReversing; 
  46.       // 先停止当前动画,然后再反向执行动画 
  47.       if (innerAnimator.isRunning()) { 
  48.           innerAnimator.end(); 
  49.       } 
  50.       innerAnimator.start(); 
  51.   } 

3.3 动画操作的实现

因为我们核心的动画值计算是基于原生的ValueAnimator,因此我们基本的动画操作也是对其执行:

  1. private AnimatorValue innerAnimator; 
  2.  
  3. // 开始动画 
  4. public void start() { 
  5.     if (innerAnimator.getLoopedCount() == AnimatorValue.INFINITE) { 
  6.         if (repeatMode == RepeatMode.REVERSE) { 
  7.             takeReverseLogic = true
  8.         } 
  9.     } 
  10.     // 对innerAnimator操作 
  11.     innerAnimator.start(); 
  12. }     
  13.  
  14. // 停止动画 
  15. public void stop() { 
  16.     // 对innerAnimator操作 
  17.     innerAnimator.stop(); 
  18.  
  19. // 取消动画 
  20. public void cancel() { 
  21.     // 对innerAnimator操作 
  22.     innerAnimator.cancel(); 
  23.  
  24. // 其他操作方法声明 
  25. ... 

总结

通过我们对原生AnimatorValue的扩展,我们实现了实际开发中大部分应用场景,让实际开发动画的效率可以大大提升。总结一下几点核心的扩展原理:

  • 视图组件动画实现:监听原生动画值进行倍率转换,再设置给组件通用属性
  • 反向/循环动画实现:监听循环动画的循环节点,反向赋值下一次动画的起始值

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2022-04-07 15:28:16

HarmonyOS鸿蒙操作系统

2022-04-13 11:24:18

ETS开发HarmonyOS鸿蒙

2022-04-14 10:10:59

Nginx开源Linux

2022-04-28 15:38:42

WebViewJavaUI

2022-04-20 20:28:40

HDF 驱动框架鸿蒙操作系统

2022-05-09 11:52:38

Java卡片服务卡片

2022-04-24 15:26:38

服务卡鸿蒙

2022-02-23 15:07:22

HarmonyOS常用控制ArkUI-eTS

2022-02-17 14:51:39

HarmonyOSJSPAI开发canvas画布

2022-02-21 15:25:47

HarmonyOS鸿蒙低代码开发

2022-03-04 16:06:33

数据库HarmonyOS鸿蒙

2022-03-02 15:59:37

HarmonyOS操作系统鸿蒙

2021-12-24 15:46:23

2022-04-07 14:33:31

操作系统鸿蒙HarmonyOS

2022-04-01 15:18:04

HarmonyHDF 驱动鸿蒙

2022-05-11 14:05:11

区块链网络安全存储

2022-05-20 14:54:33

数据安全数字化转型企业

2021-10-11 08:37:14

2022-05-16 15:35:00

漏洞黑客

2022-04-28 20:24:44

华为华为终端

同话题下的热门内容

微软 Windows 11/10 全新 One Outlook 应用开放下载:统一所有邮件微软发布 Windows 11 Dev 预览版 25120:带来全新交互式桌面内容,支持 ARM64 设备Fedora 36 通过桌面大修吸引开发者,但它能取悦 Linux 之父吗?万字多图,搞懂 Nginx 高性能网络工作原理!微软IE浏览器6月16日正式退役,是时代的眼泪微软Windows 11安卓子系统更新:底层升至 Android 12L,App 提示整合到系统通知微软宣布正式关闭 IE浏览器,历时 28 年的 IE 浏览器最终走向了终点GPIO到底该如何控制

编辑推荐

你应该知道的八款国产操作系统为什么你可能想要略过Ubuntu 17.04?HarmonyOS 2.0鸿蒙第二期开发者Beta公测申请指南让后端开发情何以堪?前端程序猿薪资大曝光谷歌“断供”华为!中国真写不出操作系统?
我收藏的内容
点赞
收藏

51CTO技术栈公众号