HarmonyOS 属性动画扩展
发布时间:2022-02-11 01:53:22 所属栏目:系统 来源:互联网
导读:HarmonyOS 提供了AnimatorValue来执行属性动画,但是其方法数很少,并且属性值范围局限于[0,1],也不直接支持动画反转等一些常用的操作。在日常开发中,我们经常需要基于这个类进行扩展编写,去适应真实场景。因此,通过收集常用的场景,整理出一个属性动画
HarmonyOS 提供了AnimatorValue来执行属性动画,但是其方法数很少,并且属性值范围局限于[0,1],也不直接支持动画反转等一些常用的操作。在日常开发中,我们经常需要基于这个类进行扩展编写,去适应真实场景。因此,通过收集常用的场景,整理出一个属性动画的扩展类ValueAnimator。 效果演示 HarmonyOS 属性动画扩展-鸿蒙HarmonyOS技术社区 实现思路 1. 动画分类 实际开发过程,我们大部分的动画都是作用于视图组件。任何复杂的动画,通过逐帧分解,最终都可以归纳为如下几种基础动画的组合: X,Y轴缩放动画 X,Y轴平移动画 透明度动画 旋转角度动画 组件宽高尺寸动画 2. 动画操作 对于动画的操作,我们可以归纳出以下这些动作: 开始动画 暂停动画 取消动画 结束动画 反转动画 设置动画起始值 设置动画延时 设置动画执行时长 设置动画插值器 设置动画状态监听 设置动画进度监听 设置动画执行次数 设置动画重复模式 设置组件动画属性值 3. 代码实现 3.1 视图动画的实现 系统原生提供的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 = 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(); } // 其他操作方法声明 ... (编辑:威海站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |