android动画的使用(上-基本用法)

动画介绍

要开发一个优秀的app,除了功能强大以外,还得有优秀的UI设计,那么,掌握自定义View以及动画是非常有必要的,今天就来讲讲动画的使用。
Android的动画可以分为三种:View动画、帧动画和属性动画。

View动画

View动画又叫做补间动画,它有四种默认动画效果:

  • 平移(Translate)
  • 缩放(Scale)
  • 旋转(Rotate)
  • 透明度(Alpha)

同时,它支持自定义动画,这个我们后面会将。

使用View动画也非常简单,主要有2种使用方式:
1. 在xml中定义动画,在代码中调用;
2. 完全用代码来写。

我们先来看下第一种使用方式

xml中定义View动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:duration="5000"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:shareInterpolator="true">

    <alpha
        android:fromAlpha="0.5"
        android:toAlpha="1">
    </alpha>

    <scale
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="0"
        android:pivotY="0"
        android:toXScale="2"
        android:toYScale="2">
    </scale>

    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="100"
        android:toYDelta="100">
    </translate>

    <rotate
        android:fromDegrees="0"
        android:pivotX="0"
        android:pivotY="0"
        android:toDegrees="360">
    </rotate>
</set>

set标签用于一系列动画组合,在后面的属性动画里我们也会用到。其中

  • android:duration代表动画时长;
  • android:fillAfter表示动画结束后View是否停留在结束位置,true表示停留在结束位置;
  • android:interpolator是指插值器,我们后面再讲;
  • android:shareInterpolator表示所有动画是否共享一个插值器,true表示共享,false表示不共享,这时需要自己给每个动画设置插值器。

关于set标签有2个属性是需要注意的:

  • android:repeatMode有restart和reverse,分别表示连续重复和逆向重复。
  • android:repeatCount表示重复的次数。

这两个属性一定要注意,在xml的set中使用是无效的,在单独的View动画中使用是有效的。

在代码中要调用这个动画也非常简单:

Animation animation = AnimationUtils.loadAnimation(
                AnimationActivity.this, R.anim.test_animation);
v.startAnimation(animation);//v此时代表一个button

下面看看效果:
这里写图片描述

就两行代码即可使用,如果是单独一个一个写animation而不是用set标签的,调用起来也非常方便,代码如下:

AnimationSet animationSet = new AnimationSet(true);

Animation anim1 = AnimationUtils.loadAnimation(AnimationActivity.this,
                R.anim.test_animation_alpha);
animationSet.addAnimation(anim1);

Animation anim2 = AnimationUtils.loadAnimation(AnimationActivity.this,
                R.anim.test_animation_translate);
animationSet.addAnimation(anim2);

animationSet.setDuration(2000);
animationSet.setFillAfter(true);
v.startAnimation(animationSet);

下面看看完全用代码如何写。

完全用代码创建View动画

直接上代码了:

AnimationSet animationSet = new AnimationSet(true);
AlphaAnimation anim1 = new AlphaAnimation(0.5f, 1f);
animationSet.addAnimation(anim1);

TranslateAnimation anim2 = new TranslateAnimation(0f, 300f, 0f, 300f);
animationSet.addAnimation(anim2);

ScaleAnimation anim3 = new ScaleAnimation(1f, 2f, 1f, 2f,
                Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);
animationSet.addAnimation(anim3);

animationSet.setDuration(2000);
animationSet.setFillAfter(true);
v.startAnimation(animationSet);

效果我就不展示了,其中要注意的是ScaleAnimation和RotateAnimation有一个旋转轴点的概念pivotX和pivotY,默认的旋转点都是控件的(0,0)处,上面代码我使用的就是左上角即(0,0)的点,具体效果大家可以自己去试试。

View动画监听器

AnimationListener,主要监听View动画的开始、重复以及结束这三个过程,使用也非常简单,如下代码所示:

animationSet.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                Toast.makeText(AnimationActivity.this, "动画开始了", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Toast.makeText(AnimationActivity.this, "动画结束了", Toast.LENGTH_SHORT).show();
            }
        });

自定义动画

创建自定义动画非常简单,只需要实现applyTransformation和initialize方法即可。在applyTransformation中完成自己想要实现的效果,在initialize中做一些初始化操作。

下面我们来看下这两个方法。

* @param width Width of the object being animated
* @param height Height of the object being animated
* @param parentWidth Width of the animated object's parent
* @param parentHeight Height of the animated object's parent
*/
public void initialize(int width, int height, int parentWidth, int parentHeight){
    }

介绍都有,四个参数,子控件长宽和父控件长宽。

* @param interpolatedTime The value of the normalized time (0.0 to 1.0)
*        after it has been run through the interpolation function.
* @param t The Transformation object to fill in with the current
*        transforms.
*/
protected void applyTransformation(float interpolatedTime, Transformation t) {
    }

第一个参数interpolatedTime为0.0~1.0的递增值,随着动画执行时间逐渐增大;而t可以用来获取初始变换矩阵Matrix,我们就是根据这个矩阵值的改变来进行动画的,并且往往会使用到Camera这个类来执行一些3D效果,下面我们看下代码实现。

/**
 * Created by bellnett on 2017/2/24.
 */

public class CustomAnimation extends Animation {

    private Camera mCamera;
    private float mCenterHeight;
    private float mCenterWdith;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);

        mCamera = new Camera();
        setFillAfter(true);
        mCenterHeight = height / 2;
        mCenterWdith = width / 2;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);

        Matrix matrix = t.getMatrix();

        mCamera.save();
        mCamera.translate(0,0,interpolatedTime * 300);
        mCamera.rotateY(interpolatedTime * 360);
        mCamera.getMatrix(matrix);
        mCamera.restore();

        /* 以高度的中心点作为旋转中心 */
        matrix.preTranslate(0,-mCenterHeight);
        matrix.postTranslate(0,mCenterHeight);
    }
}

主要做了2个操作,一个是向Z轴平移了300,另一个是绕Y轴旋转360度,至于这个camera的类,它的坐标系是3D坐标,这里就不介绍了,感兴趣的可以自己去研究。要注意的还有最后两行代码,还记得之前我们说过,scale和rotate动画的旋转点初始化都是(0,0),这里通过preTranslate和postTranslate将按钮先向上平移一半的高度,等动画结束时再平移回来,这样的效果就相当于围绕(0,height/2)这个点做动画。

使用也非常简单

CustomAnimation customAnimation = new CustomAnimation();
customAnimation.setDuration(2000);
customAnimation.setInterpolator(new LinearInterpolator());
view.startAnimation(customAnimation);

效果如下:
这里写图片描述

帧动画

帧动画的实现也非常简单,归为一下三部:

  • 在drawable中实现animation-list
  • 给控件设置背景资源setBackgroundResource
  • 实现AnimationDrawable对象
  • 开启动画

xml代码实现:

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    android:oneshot="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/a1" android:duration="1000"></item>
    <item android:drawable="@drawable/a2" android:duration="1000"></item>
    <item android:drawable="@drawable/a3" android:duration="1000"></item>
</animation-list>

其中oneshot这个属性表示动画的自动执行,false表示循环播放;true表示只执行一次,并且停留在最后一帧上。

调用代码实现:

view.setBackgroundResource(R.drawable.animation_drawable_test);
AnimationDrawable animationDrawable = (AnimationDrawable) view.getBackground();
animationDrawable.start();

效果如下:
这里写图片描述

属性动画

属性动画是在android 3.0即API 11之后才出现的,因此要兼容低版本的android系统,必须使用nineoldandroids这个动画库来兼容,这个兼容库我就不说了,感兴趣的自己去下载试试。属性动画常用的有以下三个类:ValueAnimator、ObjectAnimator以及AniamtorSet,下面我们分别讲解。

ValueAnimator

ValueAnimator从字面上看就能知道,它是一个值动画,也就是说,它不会包含具体的动画效果,只是值的变化,具体的动画需要我们根据这个值来做。那么如何使用这个ValueAnimator呢,我们分别从xml和用代码建立来讲解。

xml实现ValueAnimator

(1)首先是总布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="TestValueAnimator"
        android:text="testValueAnimator" 
        android:textAllCaps="false">
    </Button>

    <ImageView
        android:id="@+id/animatorIv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@drawable/a1" />

</LinearLayout>

很简单,一个按钮,一个图,用按钮来完成图的属性动画。

(2) 然后是动画的xml:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="50"
    android:valueTo="300"
    android:valueType="intType" >

</animator>

非常简单,值从50~300变化。

(3)下面我们看看在代码中如何调用:

public void TestValueAnimator(final View v) {
        ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater
                .loadAnimator(AnimatorActivity.this, R.animator.test_animator);
        valueAnimator.setDuration(2000);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setTarget(iv1);
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        valueAnimator.setRepeatCount(2);
        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (Integer) animation.getAnimatedValue();
                iv1.getLayoutParams().width = value;
                iv1.getLayoutParams().height = value;
                iv1.requestLayout();
            }
        });
    }

(4)看下效果图:
这里写图片描述

前面说过了,ValueAnimator只是值变化的动画,没有具体的动画效果,因此,必须实现AnimatorUpdateListener这个监听类,来监听值得变化,然后根据值的变化来实现具体的动画,在这个例子中是实现图的长宽变化。

代码实现ValueAnimator

代码实现更加方便,请看如下代码:

ValueAnimator valueAnimator = ValueAnimator.ofInt(50,300);

一句代码就能实现之前(2)中定义的动画,而且直接可以使用,不需要再调用AnimatorInflater类的loadAnimator()方法来载入动画。下面的调用和(3)中的一样,就不重复写了。

ObjectAnimator

ObjectAnimator就是可以直接实现属性动画的类了,相比ValueAnimator要使用地更加频繁,更加好用,下面我们看看ObjectAnimator的使用,也是分xml和代码实现。

xml实现ObjectAnimator

(1)总布局代码不变,直接上动画的xml实现:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="translationX"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="floatType" >

</objectAnimator>

有两点要注意:
1. 其中的valueType使用的是浮点数类型,主要是ImageView的setTranslationX方法的参数是浮点数类型的,因此我们要灵活运用。
2. 相比ValueAnimator,ObjectAnimator只比它多了一个android:propertyName参数,至于这个参数怎么填,我们可以根据我们需要设置动画的控件,输入setXXX来查看,后面XXX就是这个属性所填写的值。

(2)代码调用:

ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater
                .loadAnimator(AnimatorActivity.this, R.animator.test_animator);
        objectAnimator.setDuration(2000);
        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
        objectAnimator.setRepeatCount(2);
        objectAnimator.setTarget(iv1);
        objectAnimator.start();

和ValueAnimator差不多,只是不需要监听AnimatorUpdateListener,就能实现ImageView从0~300的X轴变化。

(3)效果图:
这里写图片描述

代码实现ObjectAnimator

代码实现也非常的简单:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv1,
                "translationX", 0f, 300f);
        objectAnimator.setDuration(2000);
        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
        objectAnimator.setRepeatCount(2);
        objectAnimator.start();

和ValueAnimator有所不同的是,在使用ofXXX方法时可以直接设定target,而无需调用setTarget()方法了,具体效果和上面的相同。

AnimatorSet

xml实现AnimatorSet

(1)总布局不变,我们看下xml中AnimatorSet的实现,和AnimationSet类似,要注意的是有一个android:ordering属性,它有两个值together和sequentially,前者代表动画一起执行;后者表示动画按顺序执行:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="together">

    <objectAnimator
        android:propertyName="translationX"
        android:valueFrom="0"
        android:valueTo="300"
        android:valueType="floatType">

    </objectAnimator>

    <objectAnimator
        android:propertyName="translationY"
        android:valueFrom="0"
        android:valueTo="300"
        android:valueType="floatType">

    </objectAnimator>
</set>

(2)然后是代码的调用,和ValueAnimator以及ObjectAnimator是一样的,只是没法设置repeatMode和repeatCount了:

AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(AnimatorActivity.this, R.animator.test_animator);
animatorSet.setDuration(2000);
animatorSet.setTarget(iv1);
animatorSet.start();

(3)看下效果:
这里写图片描述

代码实现AnimatorSet

代码实现也很方便:

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(iv1,"translationX",0f,300f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(iv1,"translationY",0f,300f);

animatorSet.playTogether(objectAnimator1,objectAnimator2);
animatorSet.start();

效果和上面是一样的,playTogether对应xml中的together;还有一个方法playSequentially对应xml中的sequentially。

PropertyValueHolder

PropertyValueHolder的使用是类似AnimatorSet的,不过它只能同步执行动画,没法按顺序执行动画。所以当要同时执行多个动画的时候,PropertyValueHolder也是个不错的选择。下面看代码:

PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX",0f, 300f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("translationY",0f, 300f);
ObjectAnimator.ofPropertyValuesHolder(iv1, propertyValuesHolder1, propertyValuesHolder2)
                .setDuration(2000).start();

效果和同步执行的AnimatorSet是一样的,效果图我就不贴了。

animate方法

animate是ViewPropertyAnimator类的一个方法,它支持链式操作,使用上算是属性动画的一种简便方式,请看如下代码:

        iv1.setPivotX(0f);
        iv1.setPivotY(0f);
        iv1.invalidate();

        iv1.animate()
                .scaleX(2f)
                .scaleY(2f)
                .alpha(0.5f)
                .setDuration(2000)
                .withStartAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                })
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                iv1.setAlpha(1.0f);
                                iv1.setScaleX(1f);
                                iv1.setScaleY(1f);
                            }
                        });
                    }
                })
                .start();

其中要注意的有以下几点:

  • 属性动画默认旋转点是中心点,因此要改变旋转点直接使用setPivotX和setPivotY,然后显示调用以下invalidate。
  • withStartAction和withEndAction都是API16添加进来的,因此如果要使用这两个方法必须api要在16及以上。
  • ViewPropertyAnimator也支持AnimatorListener和AnimatorUpdateListener,这个监听器我们在下面会讲。

下面看下效果图:
这里写图片描述

属性动画的监听器

属性动画一共有2个监听器:

  • AnimatorListener
    -AnimatorListenerAdapter
  • AnimatorUpdateListener

AnimatorListener一共有4个方法,start、end、cancel以及repeat,如果直接实现这个监听器就得重写这4个方法,不过,AnimatorListener提供了一个AnimatorListenerAdapter适配器,如果实现这个适配器的话,就可以有选择的重写以上4个方法。

AnimatorUpdateListener我们在上面讲解ValueAnimator时已经用过了,没看的请翻到上面。

下面看下代码:

        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv1,"translationX",0f,300f);
        objectAnimator.setDuration(2000);
        objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
        objectAnimator.start();
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        objectAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });

        objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

            }
        });

总结

最后我们总结一下:

  • Animation对应View动画;Animator对应Property动画。
  • View动画使用之后,按钮的位置改变了,但是点击的位置还是原来的位置;属性动画使用之后,不仅位置改变,连点击的位置也会随着改变。因此,View动画适合做一些视觉效果;属性动画适合做一些交互式动画。
  • 使用旋转和缩放时要注意旋转轴点,View动画默认是(0,0);而属性动画默认是控件的中心点。
  • 帧动画应尽量避免使用,图片一多就容易引起OOM。
  • 不管是View动画还是属性动画,单个动画都可以设置循环模式和循环次数,当多个动画组合时没法直接设置循环模式和循环次数。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值