Android动画3-属性动画(PropertyAnimation)

来源:互联网 发布:美国合法公开海关数据 编辑:程序博客网 时间:2024/05/21 06:33
注:我师父给了我很大的帮助,各位大神的帖子我也有很多参考。

属性动画是为了弥补之前两种动画模式的不足之处产生的(Android3.0之后才有的),特点是 真实对view的属性进行改动,并且能支持自定义属性动画, 基本上能实现所有能想到的动画。

属性动画是通过不断对view的属性调用set和get方法,然后重绘在界面上来达到“动画”的效果。

大纲:
       1. PropertyAnimation简单使用
        2. ValueAnimator高级用法
        3. ObjectAnimator高级用法
        4. LayoutAnimations布局动画
        5. ViewPropertyAnimator使用方法
        6. 总结

一 PropertyAnimation简单使用
    1. 使用ValueAnimator
        ValueAnimator这个类是实现属性动画的核心类,属性动画是通过不断的对目标属性的值进行修改直到等于结束值来完成的,这个类内部就会计算每一次的修改值。我们只要传入 起点值,终点值和动画总时长,这个类能计算出 起点到终点 平滑过渡的每一个点的属性值。
        使用这个类实现属性动画我们要重点关注一下几个方法:
            1. of系列方法-动画创建方法
                ValueAnimator ofFloat(float... values)  
                ValueAnimator ofArgb(int... values)
                ValueAnimator ofInt(int... values)
                ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)
                ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
                of系列方法就是用来创建ValueAnimator的方法,使用哪个方法取决于你想使属性怎样变化,如从0.1到23.5,中间值可以是小数这时选用ofFloat(),如从1到23中间都必须是整数就用ofInt(),如果是自定义对象,就要传入一个估值器(Evaluator,之后会说)。              
            2. set系列方法-动画参数设置方法
                setDuration()  动画时长
                setEvaluator()  设置估值器
                setInterpolator()  设置插值器
                setRepeatCount()  设置重复次数
                setRepeatMode()  设置重复模式  Animation.RESTART-从动画起始位置再重复动画一次      Animation.REVERSE-从当前动画结束位置倒着重复一次
                setStartDelay()  设置动画延迟时间
            3. 动画控制方法&其他方法
                cancel()    取消动画    终止当前动画的进度
                end()    结束动画    将动画状态跳到终点值(例如:从0到1的过程中,当值变为0.5时,调cancel()最后一个值就是0.5,调end()最后一个值是1,倒数第二个值是0.5)
                isRunning()    返回当前动画执行状态,  true-正在执行
                isStarted()    返回动画是否执行  true-已经执行
                pause()    暂停动画
                resume()    恢复暂停的动画
                reverse()    从当前进度倒着执行  直到到达 起点/终点
                start()    开始动画
    举几个例子:
        1.创建一个实例,添加监听器,打印数值的变化过程。数值的计算次数和线程的计算压力大小有关,当当前线程空闲时,计算次数就会比较多,繁忙时,会跳帧,跳过的帧就不会计算了。
        
        2. 创建一个实例,使用更多的参数
        
            of系列方法参数中,关于值的参数都是可变长参数。 传入1个参数,则视为从当前状态变化到参数的状态。传入2个参数,则以第一个参数为起始点,其二个参数为终点。传入更多参数,则第一个参数为起始点,最后一个为终点,中间的点都会一个一个达到(类似于折线图)。这例变化情况为0-->10-->3-->9-->12。
        3. 创建一个实例,使用ofInt,并打印数值变化过程
        
           过程   0-->10-->5,这里0,9,6重复出现是因为使用的是ofInt()方法,会对小数自动取整

    2. 使用ObjectAnimator

        ValueAnimator能计算出来这些属性值,但是貌似和动画没什么关系(其实要使用ValueAnimator直接实现动画也是可以的,不过比较麻烦),有一种更经常使用的方法来创建动画,就是使用ValueAnimator的子类ObjectAnimator。
        ObjectAnimator继承自ValueAnimator,即上述的方法ObjectAnimator都可以使用,不同的是ObjectAnimator使用of系列方法的参数有所变化,并且这个类提供了特别多的of方法供传递不同的参数,在这里就先说几个常用的比较简单的of方法。
        of系列方法:
                ofArgb(Object target, String PropertyName, int... values)
                ofInt(Object target, String PropertyName, int... values)
                ofFloat(Object target, String PropertyName, float... values)
                ofObject(Object target, String PropertyName, TypeEvaluator evaluator, Object... values)
                ofPropertyValuesHolder(Object target, String PropertyName, PropertyValuesHolder... values)
                这些of方法和ValueAnimator类的of系列方法区别就在于多了前两个参数,第一个参数是想要执行动画的view实例,第二个参数是属性动画想要更改view的属性的名称字符串。
        下面举几个例子看一下这个类的使用。    
        举几个例子:
            1. 
   
            这段代码是将给tv2设置一个动画,在5s内将其透明度从1-->0-->1。关注ofFloat()方法参数:第一个参数是 想要 实现动画的 view,第二个参数是想更改的属性名称字符串,后面几个参数是代表变化数值的可变长参数。
            2.
            
            这段代码是将tv2绕中心从0度开始旋转360度。关注ofFloat()方法:第一个参数是想要实现动画的view,第二个参数是想要更改的view的属性名称字符串,后面几个是代表变化数值的可变长参数。
            3. 
            
            这段代码是把tv2从当前位置水平位移到X坐标为-500的位置然后又移回来。关注ofFloat()方法:第一个参数是想要实现动画的view,第二个参数是想要更改view的属性名称的字符串,后面几个是代表变化的可变长参数。
            4.
            
            这段代码把tv2按照Y轴方向拉伸到2倍然后还原。关注ofFloat()方法:第一个参数是想要实现动画的view,第二个参数是想要更改view的属性名称的字符串,后面几个是代表变化的可变长参数。          

        经过这几个例子,我们会发现,这种设置动画的方式非常简单,主要是对ofFloat()方法的使用,其他方法的使用其实和补间动画有相似之处。
        
        还有一个问题是,这些of方法的第二个参数到底能传什么值,现在我们已经尝试了alpha,rotation,translationX这三个字符串实现了透明度/旋转/平移动画,到底还能传入什么值呢?这些of方法的第二个参数能传入的值是任意的,前提是传入的属性名称要有对应的get/set方法,因为属性动画是通过不断调用一个属性的get/set方法来对其值进行更改,然后在界面上重绘view完成的,故如果一个属性没有get/set方法肯定是不能使用属性动画对此属性进行动画操作的。反过来讲,只要一个属性有对应的get/set方法,那么就可以使用属性动画的方式对其属性进行动画操作。
        例:
        在view类中,
        alpha      透明度改变
                     
        rotation       旋转
                      
        translationX       X轴方向平移     translationY-Y轴方向平移
                             
        scaleX       X轴方向缩放      scaleX-X轴方向缩放
                    
        补充: 你可能已经发现了,当时旋转和缩放可以设置中心点,而ValueAnimator和ObjectAnimator都没有提供设置中心点的方法,此时,我们就要调用view.setPivotX和view.setPivotY设置中心点。
    
    3. 使用组合动画
        我们在定义补间动画的时候就使用过AnimationSet来让多个动画效果同时执行,现在属性动画怎么达到这种效果呢?
        Android提供了AnimatorSet类来完成组合动画的定义。
        实现方法:
            1. 定义多个属性动画
            2. 定义AnimatorSet
            3. 调用AnimatorSet的一些方法组合动画
            4. 调用AnimatorSet的一些方法设置动画的一些参数
            5. 调用AnimatorSet.start()方法开始动画

        AnimatorSet类直接继承自ValueAnimator类,和ObjectAnimator类同级。
        AnimatorSet类主要方法:
            play系列: 
                playTogether(Animator... items)   同时执行传入的动画
                playTogether(Collection<Animator> items)  同时执行传入的动画
                playSequentially(Animator... items)    顺序执行传入的动画(写在前面就先执行)
                playSequentially(List<Animator> items)    顺序执行传入的动画(写在前面就先执行)
                play()  这个方法是重中之重,这个方法会返回一个AnimatorSet.Builder对象,这个对象有四个方法,分别是:
                    with(Animator anim)    将现有动画和传入的动画同时执行
                    before(Animator anim)    将现有动画插入到传入的动画之前执行
                    after(Animator anim)    将现有动画插入到传入的动画之后执行
                    after(long delayMills)    将现有动画延迟指定毫秒后执行
                    注:这四个方法都会返回Builder对象,即这四个方法可以连着使用。   
            举个例子:
                              
   
    4. 使用Animator监听器
        Animator类提供了一个addListener()方法,传入相应的监听器就行了。
        使用1:
                
        使用2:如果只想重写这些监听方法里的一个或者两个,可以使用new AnimatorListenerAdapter,这个类继承AnimatorListener,是个抽象类,已经实现了这些监听方法,new这个,你只需要重写自己需要的监听方法就行了,不需要每个方法都实现。
                
                可以看到你只需要重写想要的方法即可,并且该类多提供了两个方法,分别是监听 动画暂停时(Pause)和 动画重新开始时(Resume)。

    5. 使用XML定义属性动画
        1. 在Res目录下创建animator文件夹
                
        2. 在xml文件中定义属性动画
                可以看到,xml下有三种标签可以用:
                
                分别对应:
        举例:
                
                将一个view的alpha从1变成0
            
                
                实现各种组合动画,<set/>标签下的 ordering 属性设置为 together就是同时播放动画, sequentially就是顺序执行动画。

        3. 在代码中实现属性动画
            
                setTarget()方法就是用来设置 实现动画的view的。
                最后调用start方法开始动画就OK了。


二 ValueAnimator的高级用法
        
        之前已经简单说过ValueAnimator可以实现对 值 的“动画操作”(将值从初始值变道最终值),这个类究竟是怎么做到的呢?这是后就要说一下TypeEvaluator(估值器)。
        TypeEvaluator是android.animator包下的一个接口,其已经实现的子类有ArgbEvaluator,FloatEvaluator,IntEvaluator,RectEvaluator。每次我们调用ValueAnimator的of系列方法的时候就会间接调用相应的Evaluator,当调用of方法的时候内部会先计算出来应该确定在哪些时间点 计算属性值(重绘view),然后根据这些时间点对应的进度计算 值 的相关属性值,Evaluator就是用来根据进度计算值的。
        FloatEvaluator源码:
            
            由源码可以看出,计算方法是: 起点数值+ 要变化的数值*当前进度
        IntEvaluator源码:
            
            由源码可以看出,计算方法和Float一样。
    
            看过这两个类的源码,基本能看出来,写一个类实现TypeEvaluator接口,我们就能自定义估值器,而估值器决定了某一时间点(进度)的计算值,也就是说我们可以自由定义  值  的变化曲线(view的变化曲线)。进一步我们可以自定义值的修改方法来使ValueAnimator可以对任意对象进行“动画操作”。
            (这和Interpolator刚好相反,Interpolator是通过修改当前时间点(进度)的应该显示的时间点来改变 值(view)  的变化曲线,而估值器是通过对当前时间点(进度)的 值 进行修改来达到目标。)

            举例: 自定义Evaluator使ValueAnimator对自定义bean进行“动画操作”。
                1. 自定义bean
                    
                    定义了 x y z 三个变量,并添加全参构造和get/set(get/set非常重要,属性动画就是对get/set进行操作的!),为了显示结果,我重写了toString()方法,但是这个不必要,所以没有在代码中展示。
                2. 自定义Evaluator
                    
                    简单起见我也使用了 系统定义的计算方法。 你可以实现更复杂的方法,例如:x坐标按比例变化,y坐标按自由落体公式变化,这就是一个抛物线。
                3. 使用ValueAnimator.ofObject()方法
                    
              4. 结果:
                
                
               这样就实现了 任意 对象 值的 “动画”操作。还可以进一步,如果我们将上述这些代码放在一个自定义View中使用,并且让view绘制的图形和坐标有关系,那么坐标不断变化,view就是真的在进行“动画”。这个例子写法很简单,比如以x/y坐标画个圆形/矩形,那么x/y变化的时候,矩形也就跟着跑了,代码就不写了。

            这就是 ValueAnimator 的高级用法 ---- 自定义 对象 的动画操作(自定义view的运动曲线)。


三 ObjectAnimator的高级用法

         经过上面对ValueAnimator高级用法的解释,可能你也想到了,ValueAnimator可以对 值 的变化曲线做自定义处理,到了ObjectAnimator这里那肯定就是对 要变化 的属性 进行自定义处理了。(貌似没什么关系。。。)
          
        先看下系统提供的对颜色属性改变的方法:
        
        这里的属性名称参数 必须 填写 backgroundColor ,填写color没有效果(因为此时测试用的view是TextView,该类没有提供直接操作color属性的方法,对背景颜色修改要使用backgroundColor)。
        
        此时我就是想要在属性名称参数这里填 color 该怎么处理? 此时就要用到ObjectAnimator的高级用法了。
        举例: 
            1. 写个自定义View,继承TextView(TextView里面没有对color操作的方法,故需要自己写一个)
                
                贴上源码,重点是 color属性的set/get方法,set方法中我把颜色设置给画笔,然后重绘view。即当动画执行的时候,不断调用set方法给画笔设置颜色然后重绘view。
        2. 调用ofArgb()方法,此时我使用的是 系统提供的计算颜色变化的估值器
                
                这是系统提供的计算颜色变化的估值器源码。
                然后我调用ofArgb()方法
                
                此时,我传入的属性名称参数就是 color 了,并且可以看出 可以生效。
                如果是自定义的估值器,需要调用ofObject()方法:
                ,估值器就是你自己写的计算方法了。这里我偷个懒,调用系统的估值器计算颜色变化。

        这就是 对  自定义属性  进行 动画操作的过程。
            1. 对自定义属性设置set/get方法
            2. 对自定义属性的变化函数进行设置,即估值器
            3. 使用ofObject方法,然后设置动画的一些参数(时间之类的),最后start()即可
     
        以上就是ObjectAnimator的高级用法 ---- 对 自定义属性 进行动画操作。  
    
四 LayoutAnimations布局动画(这段大部分复制hongyang大神的。)
        
    布局动画是用来对一个ViewGroup控件添加/取消childView的过程设置的动画。
    总共提供了四种方式:        

LayoutTransition.APPEARING 当一个View在ViewGroup中出现时,对此View设置的动画

LayoutTransition.CHANGE_APPEARING 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画

LayoutTransition.DISAPPEARING  当一个View在ViewGroup中消失时,对此View设置的动画

LayoutTransition.CHANGE_DISAPPEARING 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画

    举例说明:

        

        

        

        重点是LayoutTransition对象,我们是使用了该对象的setAnimator方法,这个方法第一个参数是动画类型,传入的参数就是上面说的四种类型;第二个参数就是动画对象。 
        这样的代码就实现了 给 GridLayout 布局添加childView时候的动画效果。
        这样的效果是官方默认的,我们可以通过下面的方法自定义动画效果。
        
        设置添加childView的动画为X轴缩放,从0到1。  
       

五 ViewPropertyAnimator使用方法
    ViewPropertyAnimator类是在Android3.1引进来的,为了简化属性动画的定义语法。该类继承自android.View类。3.1版本之后View类增加了一个方法animate()。
    animate()方法可以返回一个ViewPropertyAnimator对象,我们来看一下这个类里面提供了哪些方法吧。
    ViewPropertyAnimator类方法:
        (方法都很简单,就不一个一个细细说明了。毕竟是为了简化语法嘛。)


    
    使用这些方法非常简单。
    举例:
        1. tv2 移动到点(500, 500)
        
        2. tv2 移动到点(500, 500),设置时长为5s
        
       3. tv2 移动到点(500, 500),设置时长为5s,设置插值器为反弹插值器
        
       4. tv2 移动到点(500, 500),设置时长为5s,设置插值器为反弹插值器,同时设置透明度改变。
        
       5. 在4的基础上,设置缩放动画
        
        结果为:    
                
        这些方法已经可以实现简单的  平移、缩放、透明度、旋转 动画了。
        这个类中还有其他方法,但是这毕竟是为了简化语法,语法简化了功能当然就简单了,我觉得不必过于纠结这个类的每一个方法到底什么用,当实现简单动画的时候想起来用一下这些常用方法就行了,如果这些常用方法不行,那就直接用常规写法。


    小结:1. 调用这些方法的入口是 调用 view.animate() 方法。
              2. 除了start()/cancel()方法其他方法都会返回一个ViewPropertyAnimator,这个当然就是为了可以写出连缀语句。
              3. 这个类返回ViewPropertyAnimator对象的方法内部都会自己调用start()方法启动动画,所以可以不手动调用start()方法。            
           

六 总结
   
   属性动画的运行过程: 
     ValueAnimator/ObjectAnimator ----> TimeInterpolator ----> TypeEvaluator ----> setXXX() ----> onDraw()
        先调用of系列方法-->通过插值器计算时间节点-->计算相应时间节点的属性值 --> 给对应属性赋新值--> 重绘view

1 0
原创粉丝点击