android动画

作为交互的一部分,开发Android应用的时候时常会用到动画,这样可以使应用看起来不那么死板。某些较为特定的点击可以使用有趣的动画引起注意,进而可以获取更多的点击量。随着Android系统的不断完善,其动画机制也不断地改进,如早期的帧动画和补间动画,3.0之后加入属性动画,以及之后5.x加入的SVG矢量动画等。以下讲一些较为常用的动画实现方式,即帧动画、补间动画和属性动画。

逐帧动画(Frame Animation)

逐帧动画也称之为Drawable Animation,是通过一系列的图片按顺序播放使其连成动画,这里每一帧都有对应的图片。例如我需要将名字为“droidman01”到“droidman16”的16张图片连成帧动画动画,那么实现方式如下 
XML中: 
将每一帧的图片放入res的drawable中然后再res的anim中(没有则新建一个Directory命名为anim)或是Android Studio的drawable中新建一个动画XML文件,使用标签来定义各个帧动图片的顺序,通过标签来排列。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/droidman01"
        android:duration="150"
        />
    <item android:drawable="@drawable/droidman02"
        android:duration="150"
        />
...
</animation-list>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
imageView.setImageResource(R.drawable.frameanim);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
  • 1
  • 2
  • 3

这里的oneshot表示是否只执行一次,为false则执行一次就结束动画,为true当然就是循环播放。android:duration则是该帧图片播放的持续时间。 
java代码中

AnimationDrawable animationDrawable = new AnimationDrawable();
for (int i = 1;i<16;i++){
    int id;
    if (i<10){
        id = getResources().getIdentifier("droidman0"+i,"drawable",getPackageName());
    }else{
        id = getResources().getIdentifier("droidman"+i,"drawable",getPackageName());
    }
    Drawable drawable = getResources().getDrawable(id);
    animationDrawable.addFrame(drawable,150);
}
imageView.setImageDrawable(animationDrawable);
animationDrawable.setOneShot(false);
animationDrawable.start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里会看到一个方法getIdentifier(),这个方法是用来获取资源id的。第一个参数是资源名,第二个参数是资源类型可以为null,第三个参数是包名,也可以为空。这个方法对于获取资源名称类似的很有用,很方便。这里通过addFrame方法传入每帧的图片,并设置播放时间,同样代码中可通过setOneShot方法设置是否循环播放,最后通过start()方法开始播放动画。除此之外AnimationDrawable还提供其他方法如: 
stop():停止播放动画 
isRunning():放回boolean类型表示动画是否正在播放中 
run():继续从下一帧开始播放 
getNumberOfFrames():获取总帧数 
getFrame(int index):获取指定帧图片 
getDuration(int i):获取指定帧播放时间 
isOneShot():是否是一次播放 
上面动画的效果: 
这里写图片描述

补间动画(Twwen Animation)

补间动画无需定义每一帧,只需定义开始和结束的关键两帧,中间的变化可设置插值器(Interpolator)来平滑过渡。补间动画提供了四个基本类型的动画:AlphaAnimation、RotateAnimation、TranslateAnimation和ScaleAnimation。其实这些动画使用起来相对不难,只要知道各个参数的含义即可。一下就一一说明。

AlphaAnimation

// 参数分别为开始和结束时的透明度,参数的取值区间[0,1]的float类型,即全透明到完全不透明。
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
  • 1
  • 2

RotateAnimation

// 两参数分别为动画开始时的旋转角度和动画结束时的旋转角度,以点(0,0)为中心旋转
RotateAnimation rotateAnimation1 = new RotateAnimation(0,360);
// 旋转角度从0度到360度,旋转中心为点(100,100)
RotateAnimation rotateAnimation2 = new RotateAnimation(0,360,100,100);
// 旋转角度从0到360度。X轴方向上的旋转参考类型,相对参考类型的X坐标位置,Y轴方向上旋转的参考类型,相对参考类型的Y坐标位置,
// 此处参考类型有RotateAnimation.RELATIVE_TO_SELF自身,RotateAnimation.ABSOLUTE绝对位置,RotateAnimation.RELATIVE_TO_PARENT父控件,
// 如该写法为以自身的中心位置旋转
RotateAnimation rotateAnimation3 = new RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_SELF,0.5F,RotateAnimation.RELATIVE_TO_SELF,0.5F);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

TranslateAnimation

// 参数分别为动画开始X坐标,动画结束X坐标,动画开始Y坐标,动画结束X坐标。即动画效果是从(0,0)平移到(200,300)位置
TranslateAnimation translateAnimation1 = new TranslateAnimation(0,200,0,300);
// 和旋转的一样,有着参考类型,该效果为从该控件的(0,0)开始到控件宽高的2倍位置
TranslateAnimation translateAnimation2 = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,0F,TranslateAnimation.RELATIVE_TO_SELF,0F,
    TranslateAnimation.RELATIVE_TO_SELF,2F,TranslateAnimation.RELATIVE_TO_SELF,2F);
  • 1
  • 2
  • 3
  • 4
  • 5

ScaleAnimation

// 参数分别为动画开始时的X轴坐标伸缩尺寸,动画结束时X轴伸缩尺寸,动画开始时Y轴伸缩尺寸,动画结束时Y轴伸缩尺寸。其中尺寸数值为该空间原始大小的倍数。
// 该效果为以点(0,0)开始向外放大2倍
ScaleAnimation scaleAnimation1 = new ScaleAnimation(0f,2f,0f,2f);
// 前四个参数与上一样,后两个为缩放中心
ScaleAnimation scaleAnimation2 = new ScaleAnimation(0f,2f,0f,2f,100,200);
// 前四个参数与上一样,后四个为参考类型和参考相对位置,如此效果为以自身中心X,Y轴都伸展为原来的2倍
ScaleAnimation scaleAnimation3 = new ScaleAnimation(0f,2f,0f,2f,ScaleAnimation.RELATIVE_TO_SELF,0.5F,ScaleAnimation.RELATIVE_TO_SELF,0.5F);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用时只需设置动画时间即可开启动画,以透明动画为例,其他用法类似

//动画持续时间
alphaAnimation.setDuration(1000);
//动画结束时保留状态
alphaAnimation.setFillAfter(true);
//设置插值器
alphaAnimation.setInterpolator(new LinearInterpolator();
//开启动画
imageView.startAnimation(alphaAnimation);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

动画叠加AnimationSet

AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(2000);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation1);
animationSet.addAnimation(translateAnimation1);
animationSet.addAnimation(scaleAnimation1);
imageView.startAnimation(animationSet);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过AnimationSet的addAnimation方法可将各动画添加进来,然后设置时间即可。

动画监听

animation.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        // 动画开始时
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        // 动画结束时
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
        // 重复动画时
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

我们常常会在动画执行的开始或者结束时做一些相应的操作,此时就会需要监听动画的执行过程。如一个动画之后执行另一个动画等。

属性动画(Property Animation)

Android 3.0之后引进了属性动画,相较于之前的动画,属性动画真实改变了View的属性,而之前的那两种动画则只是视图上的改变,其触发位置仍旧没有变化,因此属性动画更适合做一些需要交互较强的动画。

ObjectAnimator

属性动画常用到的一个类就是ObjectAnimator,它是属性动画中最重要的一个执行类,继承自属性动画中最重要的类ValueAnimator。ObjectAnimator使用起来也相对较方便,只要记得第二个参数所要执行的动画即可,因为这里所填的是第一个参数对象的属性,且这个属性必须有get、set方法。我们以一个简单的用法来说明

ObjectAnimator objectAnimator =ObjectAnimator.ofFloat(imageView,"translationX",-300,300);
objectAnimator.setDuration(2000);
// 设置播放次数。如果为ValueAnimator.INFINITE表示无限播放下去
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
// 设置播放重复模式。RESTART表示重新开始动画,REVERSE表示动画反过来播放。
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过ObjectAnimator的工厂方法创建对象,其中第一个参数是要操作的View,第二个参数是要操作的属性,第三个参数是对应的属性变化,其是一个可变数组,即后面可继续添加参数,如这个效果就是将imageView控件在X轴方向的位移。第三个参数及其之后的参数为关键转折点。重点说下第二个参数,我们对View的动画操作常用的有(即第二个参数的值):
pivotX和pivotY:设置View的支点位置,默认为View的中心点 
translationX和translationY:View的X轴和Y轴的偏移量,或者说位移距离。 
rotation、rotationX和rotationY:View围绕支点,分别以Z轴、X轴和Y轴旋转,其中Z轴垂直屏幕。 
scaleX和scaleY:View以支点做缩放。 
x和y:直接设置View的位置,相当于原位置移动x和y距离。 
alpha:设置View的透明度,1不透明,0全透明。 
那么之前所说的set和get和这些值有什么关系呢?我们会有这些值,是因为内部通过java反射机制来调用set函数修改对象的属性值,我们打开源码ImageView继承View,而View中有一系列的函数,即方法。我们可以发现这些可以改变View属性的方法,如setTranslationX/getTranslationX、setRotationX/getRotationX等,这才使得属性动画能够找到这些方法并对其属性值做更改。

PropertyValuesHolder

PropertyValuesHolder使用起来和ObjectAnimator一样,只是它可以通过ObjectAnimator的ofPropertyValuesHolder方法将各个效果叠加起来,和AnimationSet类似。其使用方法如下,效果是在移动同时进行缩放操作。

PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",200f);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0f,1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0f,1f);
ObjectAnimator.ofPropertyValuesHolder(imageView,pvh1,pvh2,pvh3).setDuration(2000).start();
  • 1
  • 2
  • 3
  • 4

ValueAnimator

ValueAnimator是属性动画中最重要的一个类,继承自Animator。它定义了属性动画中大部分的功能,如计算各帧的属性值、处理更新事件、根据属性值得类型知道操作的属性对象而做相应的计算规则的控制。也就是说ValueAnimator其实本身不负责动画的执行,更重要的是动画执行过程中数据的获取。可以根据需要设置动画持续的时间、插值方式、重复次数等,然后启动动画。使用时一般需要注册AnimatorUpdateListener监听器。然后再监听器中获取实时数值,之后将得到的数值设置到需要的地方。用法大致如下:

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
valueAnimator.setTarget(imageView);
valueAnimator.setDuration(2000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value = (Float) animation.getAnimatedValue();
        // TODO 使用获取来的值
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

AnimatorSet

视图动画有同感AnimationSet将各个动画叠加,属性动画当然也有,那就是AnimatorSet,相较于之前的PropertyValuesHolder,AnimatorSet可以更好地控制各个动画的顺序,如用AnimatorSet实现如上面PropertyValuesHolder一样的动画效果

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView,"translationX",200f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView,"scaleX",1f,0f,1f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView,"scaleY",1f,0f,1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);
animatorSet.start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在此AnimatorSet还提供不同的方法来调整各个属性动画的顺序。如:

// 三个动画同时播放
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);
// 三个动画按顺序播放
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3);
// objectAnimator1动画与objectAnimator2动画同时播放
animatorSet.play(objectAnimator1).with(objectAnimator2);
// objectAnimator1动画在objectAnimator2动画播放之前进行,即先播放1动画再播放2动画
animatorSet.play(objectAnimator1).before(objectAnimator2);
// objectAnimator1动画在objectAnimator2动画播放之后进行,即先播放2动画再播放1动画
animatorSet.play(objectAnimator1).after(objectAnimator2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

animate方法给View设置动画

在系统3.0之后,如果动画只执行一次,则可以考虑使用animate()方法来完成动画。即View调用animate()。其简单使用例子如下。

imageView.animate()
        .translationX(200f)
        .scaleX(2f).scaleY(2f)
        .setDuration(2000)
        .withStartAction(new Runnable() {
    @Override
    public void run() {
        // 动画开始
    }
}).withEndAction(new Runnable() {
    @Override
    public void run() {
        // 动画结束
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

            }
        });
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这里调用animate()方法实际是活的一个ViewPropertyAnimator对象,其实际也是属性动画。但这里的属性不是可变数组,且不能设置重复播放。因此用于简单动画叠加或者一次性播放的还是挺方便的。

动画事件的监听

在属性动画执行的过程中,如果需要在某个执行过程做其他操作,则需添加监听事件

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) {
        // 动画重复时
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

如果只想单独监听某个事件则注册监听AnimatorListenerAdapter即可选择需要的事件对其进行监听。

objectAnimator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
    }

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

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

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

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

    @Override
    public void onAnimationResume(Animator animation) {
        super.onAnimationResume(animation);
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

XML中定义属性动画

在res目录下创建anim或是animator文件夹,并新建一个根标签为objectAnimator的xml文件

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType">
</objectAnimator>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在代码中使用

Animator animator = AnimatorInflater.loadAnimator(this,R.animator.objectanim);
animator.setTarget(imageView);
animator.start();
  • 1
  • 2
  • 3

这里重点讲的篇代码中的使用,XML中其实都差不多,只要记住各个属性的含义即可。关于插值器(Interpolators)其函数效果可看这篇(蛮看吧o(╯□╰)o)几种常用的Interpolator(插值器)的动画效果

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值