HarmonyOS 属性动画扩展

Posted HarmonyOS技术社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HarmonyOS 属性动画扩展相关的知识,希望对你有一定的参考价值。

作者:卢日见

简介

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

效果演示

实现思路

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();
    

    // 其他操作方法声明
    ...

总结

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

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

    代码地址

属性动画扩展示例

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

想了解更多关于鸿蒙的内容,请访问:

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

https://harmonyos.51cto.com/#bkwz

::: hljs-center

:::

以上是关于HarmonyOS 属性动画扩展的主要内容,如果未能解决你的问题,请参考以下文章

HarmonyOS - 纯CSS实现吹灭蜡烛动画

HarmonyOS- 基于ArkUI(eTs)实现猫头鹰动画

视图属性+对象动画组件ViewPropertyObjectAnimator

Harmony OSArkUIets开发 图形与动画绘制

css 扩展动画 - 使用animate.css。提供数据属性以在页面上的任何元素中添加动画。触发sc上的动画

css 扩展动画 - 使用animate.css。提供数据属性以在页面上的任何元素中添加动画。触发sc上的动画