Android当中的动画4—Property动画

前言

       博主在前面几篇博客 当中主要和大家聊了聊Android当中的Tween Animation,但是大家都知道,我们在工作的时候由于Tween Animation的局限性,我们很少使用它,但是为什么我们又要去花时间去了解它呢?因为我们开发重要的是一种思路,所以我们学习的是它的设计思路,而我们现在使用最多的属性动画,也就是在这个思路的基础上去实现的。如果我们明白了它的设计思路,那么我们可以不局限于它的框架,我们可以做自己的动画。好了,扯歪了,下面我们进入今天我们的要聊的主题,属性动画。

正文

       属性动画,说白了就和它自己的名字是一样的,就是对其属性进行修改,那么我们不断地去给某一个属性值进行递增的效果,比如我们X的座标,那么我们的View就会不断的沿着X的方向运动起来,那么X的座标就是我们这里所说的属性,我们要修改的就是X座标,

       首先我们要明白,属性动画实在Android3.0开始才有的新的动画框架,因为Tween 动画系统已经在android.view.animation中定义了许多的值,所以在此可以使用属性动画系统的值。在类Aimator中提供了用于创建动画的基本结构,但是通常不能直接是使用这个类,因为其中仅仅提供了一些最基本的功能,必须将其扩展到完全支持的动画值才行,下面说说类Animator中的扩展类

ValueAnimator

属性动画主要的计算器,也用于计算属性动画的值,该子类拥有所有的核心的功能,能够计算动画的值并且包含每个动画,可以设置动画是否重复,还可以设置自定义类型的功能,(我们可以直接的理解他就是一个计算机,负责计算动画过程中的过度值)

ObjectAnimator

这个类就是ValueAnimator的子类,允许设置一个目标对象和对象的属性进行动画,当计算出一个新的动画值的时候,会自动的更新相应的属性,因为有ValueAnimator的支持,使用ObjectAnimator对象,我们需要关心的也会变得特别的简单,我们只需要知道我们的起始和结束,就Ok了

AnimatorSet

这个类大家可以理解为管理每一个动画执行顺序的动画集合,我们可以去设置动画的组织方式,使多个动画相关联的运动起来,可以给动画设置一起播放顺序播放以及指定延迟播放的效果。

刚刚也说过了,属性动画就是不断地去修改属性,下面介绍一下常用的属性都有哪些,

translationX,和 translationY:这两个属性控制View对象的在布局容器当中的位置,注意他是△dx,△dy,就是增量,不是绝对位置

x,y:这两个属性控制View对象的在布局容器当中的位置,它两个就是绝对位置

rotation、rotationX 和 rotationY: 这三个属性来控制View对象围绕支点进行Z,X,Y轴进行旋转。

scaleX和scaleY:围绕View对象的支点去做比例的缩放,注意是比例,

alpha:表示View对象的透明度,默认值是1表示不透明,0表示完全透明

pivotX 和 pivotY:就是上述当中的支点位置。

       当然我们也可以自定义属性,不过我们得给这个属性提供get,set方法,因为内部会通过Java反射机制来调用set方法修改对象属性值


       了解过了我们属性动画的相关API之后,我们先来做这样一个小Demo,我们直接去访问我们View的属性,让它随我们的点击去直接改变位置



其实我们什么都没有做,点击Button,直接去设置它的内部属性

    /** 复原 */
    public void enable(View view){
        mImage.setRotationX(0);
        mImage.setRotationY(0);
    }

    /** 点击旋转X45° */
    public void animatorX(View view){
        mImage.setRotationX(45f);
    }

    /** 点击旋转Y45° */
    public void animatorY(View view){
        mImage.setRotationY(45f);
    }

那不断地去设置旋转的值,那么我们的动画是不是就可以动起来了,然后我们尝试使用一个for循环来这么做,但是我们发现,由于程序太快了我们根本就不能控制,下面我们就介绍另外一个类ValueAnimator,这个类刚刚大体介绍过,就是计算,那他计算什么呢,他可以在起始值到结束值之间做一个平滑的变换,当然如果你使用了插值器(Interpolators)的话,会根据你插值器里面定义的方法规则去做一个值得变化。下面我们就使用我们的代码去研究一下,这个类应该怎么使用

  ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                mImage.setRotation(animatedValue);
                Log.i("suansuan","animatedValue = " + animatedValue);
            }
        });


I/suansuan( 3373): animatedValue = 1
I/suansuan( 3373): animatedValue = 1
I/suansuan( 3373): animatedValue = 2
I/suansuan( 3373): animatedValue = 4
I/suansuan( 3373): animatedValue = 5
I/suansuan( 3373): animatedValue = 6
I/suansuan( 3373): animatedValue = 7
I/suansuan( 3373): animatedValue = 9
I/suansuan( 3373): animatedValue = 10
I/suansuan( 3373): animatedValue = 12
I/suansuan( 3373): animatedValue = 13
I/suansuan( 3373): animatedValue = 15
I/suansuan( 3373): animatedValue = 17
I/suansuan( 3373): animatedValue = 19
I/suansuan( 3373): animatedValue = 21
I/suansuan( 3373): animatedValue = 23
I/suansuan( 3373): animatedValue = 25
I/suansuan( 3373): animatedValue = 28
I/suansuan( 3373): animatedValue = 30
I/suansuan( 3373): animatedValue = 32
I/suansuan( 3373): animatedValue = 35
I/suansuan( 3373): animatedValue = 37
I/suansuan( 3373): animatedValue = 40
I/suansuan( 3373): animatedValue = 42
I/suansuan( 3373): animatedValue = 45
I/suansuan( 3373): animatedValue = 48
I/suansuan( 3373): animatedValue = 50

我们可以看到在0到50之间做了一个很完美的平滑的增量,而且我们的动画也很完美的动起来了,我们看到在这里我们使用了ValueAnimator.AnimatorUpdateListener监听,这个监听在动画的每一个帧上调用在这个监听使用getAnimatedValue()方法获取计算出来的值此监听一般只用于ValueAnimator。另外可能需要在这个方法当中调用View.invalidate()方法来刷新屏幕显示。

上面就是关于属性动画的核心内容,下面我们开看一下属性动画的封装,来进一步了解属性动画吧,

ObjectAnimator这个类就是直接给一个对象去设置属性变化,比如以旋转为示例,一行代码解决

 ObjectAnimator.ofFloat(mImage,"rotationY",0f,360f).setDuration(1000).start();



OfFloat()就是对float的类型的值进行变化,相应的有ofInt,ofObject,ofArgb,之类的,而第一个参数就是目标View,第二个参数就是要去操作的属性值,第三个参数就是起始值,后面的就是结束值。ObjectAnimator就是使用了建造者模式,所以可以无限的使用.XXX().XXX().start();start()方法以后就是没有返回值,所以不能使用。

如果我们要给我们的view同时开启缩放和旋转,怎么破?如果是在TweenAnimation当中我们会想到AnimationSet,但是在我们的属性动画当中,有两种实现的办法,分别是PropertyValuesHolder,和AnimatorSet前者像是后者的轻量级实现,而前者只能操作一个View,而后者随意。我们分别用这两种办法去实现刚刚我们的需求

        PropertyValuesHolder rotationX = PropertyValuesHolder.ofFloat("rotationX", 0f,720f);
        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
        ObjectAnimator.ofPropertyValuesHolder(mImage,rotationX,scaleX,scaleY).setDuration(800).start();

我们通过使用PropertyValuesHolder把一种效果进行封装,而ObjectAnimator相当于是一个总的开关。



下面我们使用AnimatorSet来实现上面我们的需求

<span style="font-size:14px;">        ObjectAnimator rotationX = ObjectAnimator.ofFloat(mImage, "rotationX", 0f, 720f).setDuration(800);
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(mImage, "scaleX", 1f, 0f, 1f).setDuration(800);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(mImage, "scaleY", 1f, 0f, 1f).setDuration(800);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(rotationX,scaleX,scaleY);
        animatorSet.start();</span>

效果和上面是一样的所以在这里博主就不向各位展示了

我们发现,我们ObjectAnimator去组织PropertyValuesHolder节点,而我们的AnimatorSet去操作ObjectAnimator节点,如果我们在以后的开发工作当中,我们去组合使用,那么可以实现很炫的效果呢。


如果我们要求先执行旋转,再同时缩放Y,缩放X,怎么破?

其实这才是这个AnimatorSet的核心功能,那就是可以去组织动画播放的顺序,


        ObjectAnimator rotationX = ObjectAnimator.ofFloat(mImage, "rotationX", 0f, 720f).setDuration(800);
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(mImage, "scaleX", 1f, 0f, 1f).setDuration(800);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(mImage, "scaleY", 1f, 0f, 1f).setDuration(800);

        AnimatorSet animatorSet = new AnimatorSet();
//        animatorSet.playTogether(rotationX,scaleX,scaleY);
        animatorSet.play(scaleX).after(rotationX).with(scaleY);
        animatorSet.start();

AnimatorSet,提供一些组织顺序的方法,play().after().befor().with(),用户比较简单,在这里博主就不多说了



最后我们来看看属性动画的监听,我们的属性动画的监听

ObjectAnimator rotationX = ObjectAnimator.ofInt(mImage, "rotationX", 0, 720).setDuration(800);
        
        //我们可以使用AnimatorListener实现类
        rotationX.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                //动画开始
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                //动画结束
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                //动画撤销
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
                //动画重新播放
            }
        });
        
        //使用AnimatorListener的实现类AnimatorListenerAdapter,来捕捉我们需要的回调方法
        rotationX.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationStart(Animator animation) {
                
            }
        });



















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章