安卓补间动画和属性动画的区别以及实践

目录

一 、需求

二 、动画实现代码

补间动画代码

属性动画代码

三 、原理分析

四 、总结


一 、需求

需要做一个倒计时3 2 1 的动画(并且进入后台时动画不会被暂停),我们知道可以通过安卓的补间动画和属性动画来做。

时间着急的直接看结果,不急的可以慢慢往下看原理。

  • 补间动画是跟View绑定在一起的,App进入后台时,View自然就会停止绘画等一切活动(包括动画),那么自然动画也就被停止了。

  • 这个需求点就只能通过属性动画来做,因为属性动画的更新是通过AnimationHandler来进行,自然就不会收到Activity,或者View的生命周期影响。

二 、动画实现代码

我们可以看下,补间动画运行效果。可以看到,当程序退入后台,等待几秒再回来时,动画又开始继续执行。

属性动画:当程序退入后台,等待几秒再回来时,动画已执行完毕。

补间动画代码

public static <T extends TextView> void start(final T animationViewTv, final int repeatCount) {
    // 设置计时
    sCurCount = repeatCount;
    String text = String.valueOf(sCurCount);
    animationViewTv.setText(text);
    animationViewTv.setVisibility(View.VISIBLE);
    // 缩放渐变动画
    ScaleAnimation scaleAnimation = new ScaleAnimation(
            0.8f, 1.5f, 0.8f, 1.5f,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    scaleAnimation.setRepeatCount(sCurCount - 1);
    scaleAnimation.setDuration(1000);
    scaleAnimation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }
        @Override
        public void onAnimationEnd(Animation animation) {
        }
        @Override
        public void onAnimationRepeat(Animation animation) {
            // 减秒
            --sCurCount;
            // 设置文本
            if (sCurCount == 0)
                animationViewTv.setText(LAST_SECOND_TEXT);
            else {
                String text = String.valueOf(sCurCount);
                animationViewTv.setText(text);
            }
        }
    });
    animationViewTv.startAnimation(scaleAnimation);
}

属性动画代码

public static <T extends TextView> void start(final T animationViewTv, final int repeatCount) {
    // 设置计时
    sCurCount = repeatCount;
    String text = String.valueOf(sCurCount);
    animationViewTv.setText(text);
    animationViewTv.setVisibility(View.VISIBLE);

    // 缩放
    ValueAnimator scaleAnimation = ValueAnimator.ofFloat(0.8f, 1.5f, 1f);
    scaleAnimation.addUpdateListener(animation -> {
        animationViewTv.setScaleX((Float) animation.getAnimatedValue());
        animationViewTv.setScaleY((Float) animation.getAnimatedValue());
    });
    scaleAnimation.setRepeatCount(sCurCount-1);
    scaleAnimation.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {}
        @Override
        public void onAnimationEnd(Animator animation) {}
        @Override
        public void onAnimationRepeat(Animator animation) {
            // 减秒
            --sCurCount;
            // 设置文本
            if (sCurCount == 0)
                animationViewTv.setText(LAST_SECOND_TEXT);
            else {
                String text = String.valueOf(sCurCount);
                animationViewTv.setText(text);
            }
        }
    });
    scaleAnimation.setDuration(1000);
    scaleAnimation.start();
}

代码很简单,具体还得看场景选择,不过更加建议使用属性动画,因为可以有更多的可能性和变化效果。
接下来,我们具体分析一下,为什么补间动画进入后台后动画会暂停?

三 、原理分析

带着问题找答案:既然是设置Scale,那就肯定会有一个地方setScaleXsetScaleY

首先,肯定是先从ScaleAnimation源码中搜索有没有以上两个方法设置。很可惜,源码中没有找到,但是却找到类型的方法,如下:
提示:Matrix不仅可以用来缩放,还可以平移,旋转,也就是说补间动画的缩放、平移和旋转都是通过Matrix来设置,而Alpha则是通过Transformation中的一个属性来设置

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    //省略部分代码
    if (mPivotX == 0 && mPivotY == 0) {
        t.getMatrix().setScale(sx, sy);
    } else {
        t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
    }
}

OK,既然找到了设置参数的地方,那么就肯定会有地方去getMatrixgetAlpha来真正的对View进行绘制。
说到绘制,那就肯定离不开View的draw方法

为了便于理解,我们从动画设置的地方入手

animationViewTv.startAnimation(scaleAnimation);

跟一下代码,主要看setAnimation方法

public void startAnimation(Animation animation) {
    animation.setStartTime(Animation.START_ON_FIRST_FRAME);
    setAnimation(animation);
    invalidateParentCaches();
    invalidate(true);
}

把传进来的animation赋值给了mCurrentAnimation,注意这个属性,会提供getAnimation返回 mCurrentAnimation

public void setAnimation(Animation animation) {
    mCurrentAnimation = animation;
   //以下代码省略
}

getAnimation方法,继续看下这个方法的调用。

public Animation getAnimation() {
    return mCurrentAnimation;
}

可以发现,getAnimation在View的draw方法中被调用。
注意:看这个方法的注释,这个draw方法是由ViewGroup.drawChild来调用,由子View来自己负责绘制

/**
 * This method is called by ViewGroup.drawChild() to have each child view draw itself.
 *
 * This is where the View specializes rendering behavior based on layer type,
 * and hardware acceleration.
 */
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
    final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();

    boolean drawingWithRenderNode = mAttachInfo != null
            &&mAttachInfo.mHardwareAccelerated
            &&hardwareAcceleratedCanvas;

    final Animation a = getAnimation();
    if (a != null) {
        more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
        concatMatrix = a.willChangeTransformationMatrix();
        if (concatMatrix) {
            mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
        }
        transformToApply = parent.getChildTransformation();
    }

    if (drawingWithRenderNode) {
        renderNode.setAnimationMatrix(transformToApply.getMatrix());
    } else {
        canvas.translate(-transX, -transY);
        canvas.concat(transformToApply.getMatrix());
        canvas.translate(transX, transY);
    }

    return more;
}

在这里我们可以发现两个点

  • 第一个很明显的可以看到,draw方法中会去调用getAnimation,如果有,就会去执行applyLegacyAnimation,而这个方法也就是传入Transformation参数提供给具体类(ScaleAnimation)设置applyTransformation方法,也就是我们设置的缩放参数。

  • 第二个就是在这里获取了getMatrix的值来渲染到当前canvas中。其中,drawingWithRenderNode参数是用来区分是否支持硬件加速,无论结果是什么,最终都会绘制到canvas中。

接下来,可以继续跟着applyLegacyAnimation方法,最终会调到AnimationapplyTransformation方法

protected void applyTransformation(float interpolatedTime, Transformation t) {
}

这个方法是个空方法,很明显,他的具体实现由他的子类来实现,正好就是四个补间动画。

四 、总结

主要讲了两点
1.补间动画和属性动画的区别
2.补间动画的参数大小设置与如何显示到View,流程如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值