加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_宿迁站长网 (https://www.0527zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 系统 > 正文

HarmonyOS 属性动画扩展

发布时间:2022-02-10 15:34:02 所属栏目:系统 来源:互联网
导读: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();
  }
  
  // 其他操作方法声明
  ... 

(编辑:云计算网_宿迁站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!