Android从零开搞系列:动画系列(2)属性动画

转载请注意:http://blog.csdn.net/wjzj000/article/details/54384918
本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)


写在前边

动画系列好久之前写了一篇关于View动画的简单使用:
http://blog.csdn.net/wjzj000/article/details/53524646
今天就把没填完的属性动画的坑填上。关于属性动画的使用仅仅是提一提。主要来梳理插值器和估值器…


简单的使用

单方面动画

这里写图片描述

  • 翻转动画代码:
        /**
         * 我们通过ofFloat的静态方法(当然也有其他的静态方法)
         * 第一个参数是动画作用的View
         * 第二个是动画方式,比如这里写的“rotationX”:以X为中心旋转
         * 接下来的参数是动画进行的属性值
         * 这里的意思是0度到360度,也可以继续往后写,那么就会继续执行对应的动画
         */
        valueAnimator =ObjectAnimator.ofFloat(ivImage, "rotationX", 0.0f, 360.0f);
        valueAnimator.setDuration(1000);
        valueAnimator.start();
  • 平移动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "translationX", 0.0f, 360.0f,0.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
  • 透明度动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "alpha", 0.0f, 1.0f,0.0f,1.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
  • 尺寸动画代码:
valueAnimator =ObjectAnimator.ofFloat(ivImage, "scaleX", 1.0f, 1.5f,1.0f);
valueAnimator.setDuration(2000);
valueAnimator.start();
  • 重复模式代码:
//动画额外重复次数
valueAnimator.setRepeatCount(2);
/**
 * repeatMode 动画重复类型(至少要有setRepeatCount())
 * ValueAnimator.RESTART:动画将从每个新循环的开始位置重新的开始
 * ValueAnimator.REVERSE:表示动画在每次重复的时候将反转方向重新开始
 * 如果不好理解可以下下面的效果
 */
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
  • ValueAnimator.RESTART的效果:
    这里写图片描述
  • ValueAnimator.REVERSE:
    这里写图片描述

综合动画

这里写图片描述

  • 代码如下:
    animatorSet=new AnimatorSet();
    animatorSet.playTogether(
        ObjectAnimator.ofFloat(ivImage, "scaleX", 1.0f, 1.5f,1.0f),
        ObjectAnimator.ofFloat(ivImage, "alpha", 0.0f, 1.0f,0.0f,1.0f),
        ObjectAnimator.ofFloat(ivImage, "translationX", 0.0f, 360.0f,0.0f),
        ObjectAnimator.ofFloat(ivImage, "rotationX", 0.0f, 360.0f)
    );
    animatorSet.setDuration(1500);
    animatorSet.start();

监听+动画分析

  • 添加监听
valueAnimator =ObjectAnimator.ofFloat(1.0f, 1.5f,1.0f);
valueAnimator.setDuration(1000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    //动画每一帧的变化都会回调此方法
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
            float value= (float) animation.getAnimatedValue();
            ivImage.setScaleX(value);
        }
    });

注意这里的用法:
这里我们仅仅是在ofFloat中传入了想要变化的数值。其余的并没有写。(接近尾声的地方有关于此内容的梳理)
那这样的话我们会拿到什么?我们可以得到:这段时间内我们传入的值随时间的变化的值。
也就是我们在监听回调中animation.getAnimatedValue()得到的值,简单来说就是一个匀速变化的值。
ivImage.setScaleX(value);
同理我们也可以设置View的其他值…


贴一些官方的文档:

  • Animator.AnimatorListener
    • onAnimationStart() - 动画启动时调用。
    • onAnimationEnd() - 当动画结束时调用。
    • onAnimationRepeat() - 当动画重演调用。
    • onAnimationCancel()-当动画被取消调用。
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate()-称为动画的每一帧上。
    • 听此事件使用所产生的计算值ValueAnimator的动画中。要使用该值,查询ValueAnimator传递到事件对象来获取与当前动画值getAnimatedValue()的方法。实现这个监听器,如果你使用的是必需的ValueAnimator。
    • 根据什么属性或对象的动画,你可能需要调用 invalidate()一个视图强制屏幕的该区域的新的动画值重绘自身。例如,动画效果可绘制对象的颜色属性只造成对屏幕的更新时,该对象重绘自己。All of the property setters on View如setAlpha()和 setTranslationX()正确无效视图,所以你不需要调用这些方法与新的值时无效视图。

进入重点想记录的


先看代码


Evaluator

这个词不知道准备的翻译是什么,个人习惯叫估值器…
先整一个简单的Demo:

        valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(10000);
        //如果不设置,默认也是线性插值器,也就是均匀变化
        valueAnimator.setInterpolator(new LinearInterpolator()); 
        valueAnimator.setObjectValues(new PointF(0, 100));
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>(){
            // fraction = t / duration
            @Override
            public PointF evaluate(float fraction, PointF startValue, PointF endValue){
                /**
                 * fraction:0-1随插值器(Interpolator)变化而变化的值
                 * 默认是匀速变化
                 * x:水平方向的速度*时间(初始设置为100);y:1/2*g*t*t(自由落体运动的距离)
                 * View的坐标(x,y)就是对应x,y对应速度下的距离
                 * PS:
                 */
                PointF point = new PointF();
                point.x = 100 * fraction * 10;
                //这里并不好给重力加速度赋值,因为正常单位是米,这里是px...所以这里就忽略吧
                point.y = 0.5f * 98f * (fraction * 10) * (fraction * 10);
                return point;
            }
        });
        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //此处得到的就是估值器中获取的Point
                PointF point = (PointF) animation.getAnimatedValue();
                ivImage.setTranslationX(point.x);
                ivImage.setTranslationY(point.y);
            }
        });

PointF:它是个啥,说实话挺唬人…整个大写的F结尾,还挺邪乎。
说白了就是Point,一个坐标而已,内置x,y。为啥有个F…因为PointF中的x,y是浮点型的…所以Ponit中的x,y理所应当就是int型的….


Interpolator

插值器:其实上文那个Demo中有所涉及,说白了很好理解。这里简单梳理一发,一会代码奉上之后再详细走一波。
插值器和估值器可以理解是一对难兄难弟。我们在估值器的使用中,主要用的了这个值:fraction。通过fraction我们进行了一系列的计算。
fraction是一个0-1逐渐递增的浮点型值,而这个值就是由插值器计算而来。


通过源码来理解插值器

  • LinearInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    //这个方法是接口TimeInterpolator中的方法。这里直接将传入的参数input直接返回出去。
    //因为说它是均匀变化
    public float getInterpolation(float input) {
        return input;
    }
    //省略部分代码...
}

当我们调用ValueAnimator的start方法之后,start中进行对时间的计算,然后将当前动画执行的时间通过层层传递传入插值器的getInterpolation方法之中,间接的赋值给了估值器。供估计器进行相关的计算。

借用官方的图和解释:

这里写图片描述

这里写图片描述

在整个动画的进行过程中,ValueAnimator会计算出动画执行的比例( 0和1之间),计算的方法是:基于该动画的总时间和已过去的时间。所经过的分数(fraction)表示在完成动画的时间百分比,0表示0%和1的含义100%。例如,在图1中,在t的经过分率= 10毫秒将是0.25,因为总的持续时间为t = 40毫秒。

Ps:翻译的官方文档,看完官方解释感觉啥也不懂了,很绕也不好理解。
仔细捋一捋还是可以理解的,插值器和估值器二者关注的焦点就是这个fraction,它就是动画执行多长时间比上动画总时间,就是一个比例。但是说到这,是不是感觉到不对劲了?逝世的时间比总时间,这TM是个永远是个线性值啊!所以….
在这里…我们可以重写插值器中的getInterpolation方法,来手动改变这个比较。变一个说法就是,我们用一个伪造的方法来控制时间!

  • 看一段代码:
//第一个平移动画我们使用线性插值器进行均匀变化
valueAnimator0=ObjectAnimator.ofFloat(black,"translationX",0.0f,500.0f);
valueAnimator0.setInterpolator(new LinearInterpolator());
valueAnimator0.setDuration(1500);
valueAnimator0.start();

//第二个平移动画我们重写控制方法,返回时间的平方
valueAnimator=ObjectAnimator.ofFloat(red,"translationX",0.0f,500.0f);
valueAnimator.setInterpolator(new TimeInterpolator() {
    @Override
    public float getInterpolation(float input) {
        //由上文我们知道这里的input是0-1的值,因此我们返回平方,其效果会先比线性快,然后慢下来。
        return input*input;
    }
    });
valueAnimator.setDuration(1500);
valueAnimator.start();
  • 疗效好不好,看效果…
    这里写图片描述

二者都是同时到达终点,但是我们可以很明显看出黑块大部分时间都处于领先位置,也就是我们设置了平方的原因。


在今天写动画的时候,其实碰到了小小的问题,有必要在接近尾声的地方记录一下。

ObjectAnimator和ValueAnimator

让我们先看代码上的不同

//很明显我们可以看出ObjectAnimator继承ValueAnimator
public final class ObjectAnimator extends ValueAnimator

public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {

二者存在了不少的不同之处:

  • ValueAnimator:
public static ValueAnimator ofFloat(float... values) {
    ValueAnimator anim = new ValueAnimator();
    anim.setFloatValues(values);
    return anim;
}

我们可以看到这里的操作方法中传递的参数,都不含动画作用View这个参数以及像“scaleX”这样的propertyName。
因此我们如果想使用ValueAnimtor则应该这么写:

        valueAnimator=ValueAnimator.ofFloat( 0.0f,1.0f ,0.0f);
        valueAnimator.setTarget(ivImage);
        valueAnimator.setDuration(2000);
        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ivImage.setAlpha(animation.getAnimatedFraction());
            }
        });
  • ObjectAnimator:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    anim.setFloatValues(values);
    return anim;
}

PS:相关源码基本都存放于我的这个开源项目之中:
https://github.com/zhiaixinyang/PersonalCollect


尾声

收尾的有些仓促,所以有时间还是会回过头来完善的。所以希望各位看官多多包涵,如果有不理解的地方,你TM不会多看几遍!

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值