Android三种常用动画分享


FBI Warning:欢迎转载,但请标明出处:http://blog.csdn.net/codezjx/article/details/45179671,未经本人同意请勿用于商业用途,感谢支持!


Android3.0(即API Level11)以前,Android仅支持2种动画:分别是Frame Animation(逐帧动画)和Tween Animation(补间动画),在3.0之后Android支持了一种新的动画系统,称为:Property Animation(属性动画)。

 

一、Frame Animation:(逐帧动画)

这个很好理解,一帧帧的播放图片,利用人眼视觉残留原理,给我们带来动画的感觉。它的原理的GIF图片、电影播放原理一样。

1.定义逐帧动画比较简单,只要在<animation-list…/>中使用<item…/>子元素定义所有播放帧即可。

  1. <animation-list xmlns:android="http://schemas.android.com/apk/res/android"  
  2. android:oneshot="false">  
  3. <!-- 添加多个帧 -->  
  4. <item android:drawable="@drawable/frame01" android:duration="60" />  
  5. <item android:drawable="@drawable/frame01" android:duration="60" />  
  6.     <item android:drawable="@drawable/frame01" android:duration="60" />  
  7. </animation-list>  
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<!-- 添加多个帧 -->
<item android:drawable="@drawable/frame01" android:duration="60" />
<item android:drawable="@drawable/frame01" android:duration="60" />
	<item android:drawable="@drawable/frame01" android:duration="60" />
</animation-list>


(1) android:oneshot 设置是否仅播放一次

(2) android:drawable 设置每一帧图片

(3) android:duration 设置图片间切换间隔


2.习惯上把AnimationDrawable设置为ImageView的背景

android:background="@anim/frame_anim"

然后我们就可以在Java代码中获取AnimationDrawable对象了

AnimationDrawable anim = (AnimationDrawable)imageView.getBackground();

(需要注意的是,AnimationDrawable默认是不播放的,调用其start()方法开始播放,stop停止播放)

 

3.上面的动画文件是通过xml文件来配置的,如果你喜欢,也可以通过在java代码中创建AnimationDrawable对象,然后通过addFrame(Drawable frame, int duration)方法向动画添加帧,然后start()。。。

 

二、Tween Animation:(补间动画)

补间动画就是我们只需指定开始、结束的“关键帧“,而变化中的其他帧由系统来计算,不必自己一帧帧的去定义。

1. Android使Animation代表抽象动画,包括四种子类:AlphaAnimation(透明度动画)ScaleAnimation(缩放动画)TranslateAnimation(位移动画)RotateAnimation(透明度动画)Android里面允许在java中创建Animation类对象,但是一般都会采用动画资源文件来定义动画,把界面与逻辑分离

  1. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:interpolator="@android:anim/linear_interpolator">  
  3.     <!-- 定义透明度的变换 -->  
  4.     <alpha   
  5.         android:fromAlpha="1"   
  6.         android:toAlpha="0"   
  7.         android:duration="3000"/>   
  8.     <!-- 定义旋转变换 -->  
  9.     <rotate   
  10.         android:fromDegrees="0"   
  11.         android:toDegrees="1800"   
  12.         android:pivotX="50%"   
  13.         android:pivotY="50%"   
  14.         android:duration="3000"/>  
  15. </set>  
<set xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/linear_interpolator">
	<!-- 定义透明度的变换 -->
	<alpha 
		android:fromAlpha="1" 
		android:toAlpha="0" 
		android:duration="3000"/> 
	<!-- 定义旋转变换 -->
	<rotate 
		android:fromDegrees="0" 
		android:toDegrees="1800" 
		android:pivotX="50%" 
		android:pivotY="50%" 
		android:duration="3000"/>
</set>

(一个set可以同时定义多个动画,一起执行。)


2. android:interpolator="@android:anim/linear_interpolator"控制动画期间需要补入多少帧,简单来说就是控制动画速度,有些地方翻译为“插值“。Interpolator有几种实现类:LinearInterpolatorAccelerateInterpolatorAccelerateDecelerateInterpolatorCycleInterpolatorDecelerateInterpolator,具体使用可以参考官方API Demo


3. 定义好anim文件后,我们可以通过AnimationUtils工具类来加载它们,加载成功后返回一个Animation。然后就可以通过ViewstartAnimation(anim)开始执行动画了。

  1. Animation anim = AnimationUtils.loadAnimation(this, R.anim.anim);  
  2. //设置动画结束后保留结束状态  
  3. anim.setFillAfter(true);  
  4. //设置插值效果  
  5. anim.setInterpolator(interpolator);  
  6. //对view执行动画  
  7. view. startAnimation(anim);  
Animation anim = AnimationUtils.loadAnimation(this, R.anim.anim);
//设置动画结束后保留结束状态
anim.setFillAfter(true);
//设置插值效果
anim.setInterpolator(interpolator);
//对view执行动画
view. startAnimation(anim);


三、Property Animation:(属性动画)

属性动画,这个是在Android 3.0中才引进的,它可以直接更改我们对象的属性。在上面提到的Tween Animation中,只是更改View的绘画效果而View的真实属性是不改变的。假设你用Tween动画将一个Button从左边移到右边,无论你怎么点击移动后的Button,他都没有反应。而当你点击移动前Button的位置时才有反应,因为Button的位置属性木有改变。而Property Animation则可以直接改变View对象的属性值,这样可以让我们少做一些处理工作,提高效率与代码的可读性。

1ValueAnimator:包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用ValueAnimator有两个步骤

1计算属性值。

2根据属性值执行相应的动作,如改变对象的某一属性。

我们的主是第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),将要改变View对象属性的事情在该接口中do

  1. animation.addUpdateListener(new AnimatorUpdateListener() {  
  2.     @Override  
  3.     public void onAnimationUpdate(ValueAnimator animation) {  
  4.         //do your work  
  5.     }  
  6. });  
animation.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        //do your work
    }
});

 

2ObjectAnimator:继承自ValueAnimator,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:

1.对象应该有一个setter函数:set<PropertyName>(驼峰命名法)

2如下面的例子,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get<PropertyName>

3如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。

  1. ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);  
  2. oa.setDuration(3000);  
  3. oa.start();  
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.start();

如果不满足上面的条件,我们只能乖乖的使用ValueAnimator来创建动画。

 

3Animator.AnimatorListener:可以为Animator设置动画监听,需要重写下面四个方法。

  1. onAnimationStart()  
  2. onAnimationEnd()  
  3. onAnimationRepeat()  
  4. onAnimationCancel()  
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel()

//appdemo

AnimatorSet set = new AnimatorSet();
        ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationY", 0f,
                -200f);
        anim.setDuration(500);
        anim.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                GetBitMap.instance().addImage(
                        BYConfig.GETRES + "?id=" + readTeam.getBigPhoto(),
                        riv_photo, R.drawable.readteam_photo_default,
                        R.drawable.readteam_photo_default);
                // 上滑结束,开始下滑
                setPhotoAnimotionDown(view);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }
        });
        set.play(anim);
        set.start();

这里我们也可以实现AnimatorListenerAdapter,他的好处是可以只用定义想监听的事件而不用实现每个函数却只定义一空函数体。如下:

  1. anim.addListener(new AnimatorListenerAdapter() {  
  2.     public void on AnimationEnd(Animator animation){  
  3.         //do your work  
  4.     }  
  5. });  
anim.addListener(new AnimatorListenerAdapter() {
    public void on AnimationEnd(Animator animation){
        //do your work
    }
});

4AnimationSet:可以组合多个动画共同工作

  1. AnimatorSet bouncer = new AnimatorSet();  
  2. bouncer.play(anim1).before(anim2);  
  3. bouncer.play(anim2).with(anim3);  
  4. bouncer.play(anim2).with(anim4)  
  5. bouncer.play(anim5).after(amin2);  
  6. animatorSet.start();  
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();

上面的代码意思是首先播放anim1;同时播放anim2,anim3,anim4;最后播放anim5

 

5TimeInterplator:与Tween中的interpolator类似。有以下几种 加速器

AccelerateInterpolator          加速,开始时慢中间加速

DecelerateInterpolator          减速,开始时快然后减速

AccelerateDecelerateInterolator      先加速后减速,开始结束时慢,中间加速

AnticipateInterpolator         反向 ,先向相反方向改变一段再加速播放

AnticipateOvershootInterpolator     反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值

BounceInterpolator         跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为8577708090100

CycleIinterpolator         循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)

LinearInterpolator         线性,线性均匀改变

OvershottInterpolator        回弹,最后超出目的值然后缓慢改变到目的值

TimeInterpolator          一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

 

6Keyframes:可以让我们定义除了开始和结束以外的关键帧。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如下:

  1. Keyframe kf0 = Keyframe.ofInt(0400);  
  2. Keyframe kf1 = Keyframe.ofInt(0.25f, 200);  
  3. Keyframe kf2 = Keyframe.ofInt(0.5f, 400);  
  4. Keyframe kf4 = Keyframe.ofInt(0.75f, 100);  
  5. Keyframe kf3 = Keyframe.ofInt(1f, 500);  
  6. PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);  
  7. ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);  
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);

上述代码的意思是:设置btn对象的width属性值使其:开始时 Width=400,动画开始1/4时 Width=200,动画开始1/2时 Width=400,动画开始3/4时 Width=100,动画结束时 Width=500

 

7ViewPropertyAnimator:对一个View同时改变多种属性,非常推荐用这种。该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图。而且使用起来非常简便,但是要求API LEVEL 12,即Android 3.1以上。仅需要一行代码即可完成水平、竖直移动

  1. myView.animate().translationX(50f). translationY(100f);  
myView.animate().translationX(50f). translationY(100f);


8)常需要改变的一些属性

translationX,translationY: View相对于原始位置的偏移量

rotation,rotationX,rotationY: 旋转,rotation用于2D旋转角度,3D中用到后两个

scaleX,scaleY: 缩放比

x,y: View的最终坐标,是Viewlefttop位置加上translationXtranslationY

alpha: 透明度

 

四、最后自己总结一下这三种动画的优缺点

(1)Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;

(2)Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效。

(3)Property Animation(属性动画)3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大!但是目前国外有个开源库,可以提供低版本支持!有兴趣的可以参考一下http://nineoldandroids.com/


如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,那么下面我们就来看看补间动画所不能胜任的场景。

注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描述,没错,补间动画是只能够作用在View上的。也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会需要对一个非View的对象进行动画操作呢?这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。

然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。

最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值