古人已用三冬足,年少今开万卷余。这篇文章主要讲述HarmonyOS 属性动画扩展相关的知识,希望能为你提供帮助。
作者:卢日见
简介HarmonyOS 提供了AnimatorValue
来执行属性动画,但是其方法数很少,并且属性值范围局限于[0,1],也不直接支持动画反转等一些常用的操作。在日常开发中,我们经常需要基于这个类进行扩展编写,去适应真实场景。因此,通过收集常用的场景,整理出一个属性动画的扩展类ValueAnimator
。
效果演示
文章图片
实现思路 1. 动画分类实际开发过程,我们大部分的动画都是作用于视图组件。任何复杂的动画,通过逐帧分解,最终都可以归纳为如下几种基础动画的组合:
- X,Y轴缩放动画
- X,Y轴平移动画
- 透明度动画
- 旋转角度动画
- 组件宽高尺寸动画
- 开始动画
- 暂停动画
- 取消动画
- 结束动画
- 反转动画
- 设置动画起始值
- 设置动画延时
- 设置动画执行时长
- 设置动画插值器
- 设置动画状态监听
- 设置动画进度监听
- 设置动画执行次数
- 设置动画重复模式
- 设置组件动画属性值
系统原生提供的
AnimatorValue
为我们提供了[0,1]的动画范围。因此最简单的实现方式是定义一个ValueAnimator
,内部包含一个系统的AnimatorValue
来计算[0,1]的进度值,通过自己的逻辑转换为我们期望的动画值。public class ValueAnimator
private AnimatorValue innerAnimator;
// 监听动画值的变化
private final AnimatorValue.ValueUpdateListener valueUpdateListener = new AnimatorValue.ValueUpdateListener()
@Override
public void onUpdate(AnimatorValue animatorValue, float fraction)
Object[] takeValues = values;
// 动画反转运算处理
if (takeReverseLogic &
&
isReversing)
takeValues = reverseValues;
Object animatedValue = https://www.songbingjia.com/android/takeValues[0];
// fraction为[0,1]当前时间的进度,通过计算转换成实际的动画值
if (animatedValue != null)
if (animatedValue instanceof Integer)
int start = (int) takeValues[0];
int end = (int) takeValues[1];
animatedValue = start + (int) (fraction * (end - start));
else
float start = (float) takeValues[0];
float end = (float) takeValues[1];
animatedValue = start + fraction * (end - start);
currentAnimatedValue = animatedValue;
// 将当前进度值通知给外部调用者
if (updateListeners != null)
notifyOuterListener(animatorValue, fraction, animatedValue);
// 如果是组件动画,将动画值转换为视图组件的属性值变化
if (targetHolder != null &
&
targetHolder.get() != null)
updateComponentProperty((Float) animatedValue);
;
// 动画值转换为视图组件的属性变化
private void updateComponentProperty(Float currentValue)
Component component = targetHolder.get();
for (Property property : targetProperties)
switch (property)
case SCALE_X:// 缩放x
component.setScaleX(currentValue);
break;
case SCALE_Y:// 缩放y
component.setScaleY(currentValue);
break;
case TRANSLATION_X:// 平移x
component.setTranslationX(currentValue);
break;
case TRANSLATION_Y:// 平移y
component.setTranslationY(currentValue);
break;
case ALPHA:// 透明度
component.setAlpha(currentValue);
break;
case ROTATION:// 中心旋转
component.setRotation(currentValue);
break;
case WIDTH:// 尺寸宽
float width = currentValue;
component.setWidth((int) width);
break;
case HEIGHT:// 尺寸高
float height = currentValue;
component.setHeight((int) height);
break;
default:
break;
3.2 反向循环动画的实现
要执行反向循环动画,我们需要监听循环动画的每次循环节点,然后在下一次动画执行开始把动画的起始值反置。
private static final int MAX_SIZE = 2;
private final Object[] values = new Object[MAX_SIZE];
// 正向动画起始值
private final Object[] reverseValues = new Object[MAX_SIZE];
// 反向动画起始值// 设置起始值时,除了正向动画起始值,同时构建一份反向起始值
public void setFloatValues(float start, float end)
values[0] = start;
values[1] = end;
reverseValues[0] = end;
reverseValues[1] = start;
// 监听动画循环点
private final Animator.LoopedListener loopedListener = new Animator.LoopedListener()
@Override
public void onRepeat(Animator animator)
// 如果循环模式设置为反向,下次执行动画则反向执行
// 例如当前是[0,1],动画结束后就会从[1,0]开始执行,再下次又从[0,1],如此循环...
if (takeReverseLogic)
isReversing = !isReversing;
if (listeners != null)
for (AnimatorListener listener : listeners)
listener.onAnimationRepeat(ValueAnimator.this);
;
// 监听动画值的变化
private final AnimatorValue.ValueUpdateListener valueUpdateListener = new AnimatorValue.ValueUpdateListener()
@Override
public void onUpdate(AnimatorValue animatorValue, float fraction)
Object[] takeValues = values;
if (takeReverseLogic &
&
isReversing)
// 根据循环模式读取正向还是反向起始值
takeValues = reverseValues;
...
;
// 反向执行动画
public void reverse()
takeReverseLogic = !takeReverseLogic;
isReversing = !isReversing;
// 先停止当前动画,然后再反向执行动画
if (innerAnimator.isRunning())
innerAnimator.end();
innerAnimator.start();
3.3 动画操作的实现
因为我们核心的动画值计算是基于原生的
ValueAnimator
,因此我们基本的动画操作也是对其执行:private AnimatorValue innerAnimator;
// 开始动画
public void start()
if (innerAnimator.getLoopedCount() == AnimatorValue.INFINITE)
if (repeatMode == RepeatMode.REVERSE)
takeReverseLogic = true;
// 对innerAnimator操作
innerAnimator.start();
// 停止动画
public void stop()
// 对innerAnimator操作
innerAnimator.stop();
// 取消动画
public void cancel()
// 对innerAnimator操作
innerAnimator.cancel();
// 其他操作方法声明
...
总结通过我们对原生
AnimatorValue
的扩展,我们实现了实际开发中大部分应用场景,让实际开发动画的效率可以大大提升。总结一下几点核心的扩展原理:- 视图组件动画实现:监听原生动画值进行倍率转换,再设置给组件通用属性
- 反向/循环动画实现:监听循环动画的循环节点,反向赋值下一次动画的起始值 代码地址
更多原创内容请关注:深开鸿技术团队入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
想了解更多关于鸿蒙的内容,请访问:
51CTO和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com/#bkwz
::: hljs-center
文章图片
【HarmonyOS 属性动画扩展】:::
推荐阅读
- #yyds干货盘点#Python实战案例,PIL模块,Python实现自动化生成倒计时图片
- #展望我的2022Flag# 用未来可能会发生的事情推断今天该做的事
- 一个BPMN流程示例带你认识项目中流程的生命周期
- #聊一聊悟空编辑器# 2022新年的悟空编辑器
- #yyds干货盘点# 简单的文本预处理
- Adobe Reader 缓冲区溢出漏洞 (CVE-2010-2883)漏洞分析报告
- 教大家用 Springboot 返回 Json 数据及统一数据封装
- 使用 VSCode 调试 Electron 主进程代码
- 如何在表中打印重复的行()