Android动画总结

最近一周系统看了Android动画方面的知识点,总结成一篇文章,供网友参考,也供日后自己复习使用。

Android系统提供了两类动画,View动画和Property动画。

View动画从API level 1就有,Property动画从API level 11引入的。


理解

View动画

Tween 动画

View动画包括Tween 动画和 Frame动画。Tween 动画是指在给定的初始值和终点值之间做缩放,位移,旋转,透明度等变换。Frame动画是指对给定的一组Drawable资源一个接一个的显示。


动画定义可以在xml中,也可以在代码中定义,推荐xml,因为可读性好,可重用。

动画xml文件放在目录 res/anim/ 下。xml文件只能有一个根元素,这些根元素可以是 <alpha><scale><translate><rotate>  或者 <set>   ,<set>  里可以保护其他根元素和<set>  元素。

<set android:shareInterpolator="false">
    <scale
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="1.4"
        android:fromYScale="1.0"
        android:toYScale="0.6"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="700" />
    <set android:interpolator="@android:anim/decelerate_interpolator">
        <scale
           android:fromXScale="1.4"
           android:toXScale="0.0"
           android:fromYScale="0.6"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700"
           android:duration="400"
           android:fillBefore="false" />
        <rotate
           android:fromDegrees="0"
           android:toDegrees="-45"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700"
           android:duration="400" />
    </set>
</set>

使用

        View view = new ImageView(this);
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate);
        view.startAnimation(animation);  

<alpha> <scale> <translate> <rotate>  <set>  对应的类分别是 AlphaAnimationScaleAnimationTranslateAnimationRotateAnimation ,AnimationSet 。

使用

        AnimationSet animationSet = new AnimationSet(true);
        Animation alphaAnim = new AlphaAnimation(0.0f,1.0f);
        Animation translationAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f,
                Animation.RELATIVE_TO_SELF,0.0f,Animation.RELATIVE_TO_SELF,0.0f);
        animationSet.addAnimation(alphaAnim);
        animationSet.addAnimation(translationAnim);
        view.startAnimation(animationSet);
要对ViewGroup的每个child做动画,比如child进入界面时的动画,需要使用LayoutAnimationController

        ListView listView = new ListView(this);
        //create animation
        AnimationSet animationSet = new AnimationSet(true);
        Animation alphaAnim = new AlphaAnimation(0.0f,1.0f);
        Animation translationAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,1.0f,Animation.RELATIVE_TO_SELF,0.0f,
                Animation.RELATIVE_TO_SELF,0.0f,Animation.RELATIVE_TO_SELF,0.0f);
        animationSet.addAnimation(alphaAnim);
        animationSet.addAnimation(translationAnim);
        //create LayoutAnimationController
        LayoutAnimationController animationController = new LayoutAnimationController(animationSet,0.5f);
        //set LayoutAnimationController for ViewGroup
        listView.setLayoutAnimation(animationController);


Frame动画

定义帧动画的xml文件存放在 res/drawable/ 下,可以用作View的背景,调用 start()  开始动画。

spin_animation.xml

<!-- Animation frames are wheel0.png -- wheel5.png files inside the
 res/drawable/ folder -->
 <animation-list android:id="@+id/selected" android:oneshot="false">
    <item android:drawable="@drawable/wheel0" android:duration="50" />
    <item android:drawable="@drawable/wheel1" android:duration="50" />
    <item android:drawable="@drawable/wheel2" android:duration="50" />
    <item android:drawable="@drawable/wheel3" android:duration="50" />
    <item android:drawable="@drawable/wheel4" android:duration="50" />
    <item android:drawable="@drawable/wheel5" android:duration="50" />
 </animation-list>


 // Load the ImageView that will host the animation and
 // set its background to our AnimationDrawable XML resource.
 ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
 img.setBackgroundResource(R.drawable.spin_animation);

 // Get the background, which has been compiled to an AnimationDrawable object.
 AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();

 // Start the animation (looped playback by default).
 frameAnimation.start();

Property 动画

属性动画改变的是对象的属性,对象的外观也会跟着变化;而View动画,改变的只是View的外观,只改变了View的绘制区域,而起属性没有变化。(比如,一个View做位移动画后,触发点击事件的区域还在原来的位置)View动画只适用于View,而属性动画可适用于任何对象;View动画不能对background color作动画,但属性动画可以。


如果View动画能满足需求,就用它,因为View动画执行起来需要的时间和写的代码少。


通过下图看属性动画的原理


该图展示的是线性变化的动画,整个duration是40ms,每10ms x变化10.


该图展示的是非线性的,先加速后减速,第一个10ms,x变化6,第二个10ms,x变化14,第三个10ms,x变化14,第四个10ms,x变化6。



上图展示了属性动画系统主要的类,ValueAnimator继承自Animator,Animator是抽象类,定义属性动画的基本行为,ValueAnimator有属性的初始值,终点值,动画时间,时间插值器TimeInterpolator,属性值计算TypeEvaluator。通过TimeInterpolator得到一个0-1的fraction值,0表示duration的0%,1表示duration的100%,TypeEvaluator使用fraction值,计算得到属性值,比如上面的例子中,在t=10ms时,线性变化的fraction=0.25,非线性的fraction=0.15,TypeEvaluator得到的属性值分别是0.25*(40-0)=10 和  0.15*(40-0)=6。在得到属性值后ValueAnimator调用AnimatorUpdateListener,由调用者来决定如何使用变化的属性值。

ObjectAnimator继承自ValueAnimator,可以方便地使用属性动画,但前提是target对象需要有GetFoo(),SetFoo(),"foo"即是属性名。

ValueAnimator使用
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();

或者自定义 TypeEvaluator
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
但还需要给ValueAnimator设置 ValueAnimator.AnimatorUpdateListener,用于更新target的属性。

使用ObjectAnimator不需要设置ValueAnimator.AnimatorUpdateListener,只需要给出target和property name。
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

AnimatorSet使用
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

可以设置ViewGroup的layout变化时的动画。使用 LayoutTransition,viewGroup.setLayoutTransition()。但child add/remove,visible/invisble,gone时,都会触发这种动画。总共有4种情况, APPEARING,CHANGE_APPEARING,DISAPPEARING ,CHANGE_DISAPPEARING。调用LayoutTransition的setAnimator(type,animator). ViewGroup的默认layout change动画是没有打开的,在xml中可以设置
android:animateLayoutChanges="true"
多属性动画可选方式

Multiple ObjectAnimator objects

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

One ObjectAnimator

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

ViewPropertyAnimator

myView.animate().x(50f).y(100f);

属性动画也可以在xml中定义,xml文件 res/animator/  
<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();

实践

QQ客户端侧滑菜单实现

参考的网上网友的实现方案,可以直接去那里看。地址  http://www.cnblogs.com/JczmDeveloper/p/4178227.html

侧滑菜单的效果截图如下:

   


58同城Loading View实现

也是参考的网友的实现方案,地址   https://github.com/zzz40500/android-shapeLoadingView 

58同城效果


在这两个项目中,都用到了Property 动画。

    
  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值