前面一篇博客解读了Android属性动画Property Animation系列一之ValueAnimator的相关知识点以及怎么使用。这篇博客继续解读Android 属性动画 ObjectAnimator 类的使用。
相比ValueAnimator类,ObjectAnimator更加实用,因为它真正可以作用在一个对象上。不过ObjectAnimator是继承自ValueAnimator的,所以主体方法还是ValueAnimator里实现的。那么我们来看看ObjectAnimator的使用吧。常用方法有这些:ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()。
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0.0f, 350.0f, 0f); animator.setDuration(2500).start();
ofFloat()方法的第一个参数表示动画操作的对象(可以是任意对象),第二个参数表示操作对象的属性名字(只要是对象有的属性都可以),第三个参数之后就是动画过渡值。当然过度值可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 1.5f); animator.setDuration(2000).start();
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "rotationX", 0.0f, 90.0f,0.0F); animator.setDuration(2000).start();
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F); animator.setDuration(2000);//动画时间
是不是感觉很简单?两行代码就能实现一个动画效果,当然只是一个简单的动画配置,如果你需要更加好的效果动画,你可以通过这些方法去配置:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F); animator.setDuration(2000);//动画时间 animator.setInterpolator(new BounceInterpolator());//动画插值 animator.setRepeatCount(-1);//设置动画重复次数 animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式 animator.setStartDelay(1000);//动画延时执行 animator.start();//启动动画
可以根据自己的需求进行配置调整。
上面我们看到的都是单个动画,那么需要实现组合动画怎么办呢?不着急,Android工程师给我们提供了两种方法来实现,AnimatorSet类,ObjectAnimator.ofPropertyValuesHolder()方法。
这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:
after(Animator anim) 将现有动画插入到传入的动画之后执行
after(long delay) 将现有动画延迟指定毫秒后执行
before(Animator anim) 将现有动画插入到传入的动画之前执行
with(Animator anim) 将现有动画和传入的动画同时执行
好的,有了这些方法,我们来实现一个组合动画:开始图片的透明度从不透明到0.2的透明再到不透明,随着整个布局背景的颜色变化的同时ImageView先向右平移200个像素,然后再放大2倍,最后沿着X轴从0到90度再到0度的旋转。
代码如下:
ObjectAnimator animator = ObjectAnimator.ofInt(container, "backgroundColor", 0xFFFF0000, 0xFFFF00FF); ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "translationX", 0.0f, 200.0f, 0f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 2.0f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "rotationX", 0.0f, 90.0f, 0.0F); ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.2f, 1.0F); //组合动画方式1 AnimatorSet set = new AnimatorSet(); ((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4); set.setDuration(5000); set.start();
我们可以看到,先创建了5个ObjectAnimator的动画,然后 new 了一个AnimatorSet对象,将刚才5个动画play到AnimatorSet对象中执行。执行效果就是上面的效果图了。
当然你要可以使用AnimatorSet类中的playTogether(Animator… items)方法实现多个动画同时执行的效果。
除了上面Animator类还可以使用PropertyValuesHolder类来实现组合动画,不过这个组合动画就没有上面的丰富了,使用PropertyValuesHolder类只能多个动画一起执行。当然我们得结合 ObjectAnimator.ofPropertyValuesHolder(Object target,
PropertyValuesHolder… values);方法来使用。第一个参数是动画的目标对象,之后的参数是PropertyValuesHolder类的实例,可以有多个这样的实例。代码如下:
//组合动画方式2 PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("translationX", 0.0f, 300.0f); PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f); PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0F); PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0F); ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, valuesHolder, valuesHolder1, valuesHolder2, valuesHolder3); objectAnimator.setDuration(2000).start();
同样,我们也是先创建了4个PropertyValuesHolder类的动画,然后通过ObjectAnimator.ofPropertyValuesHolder()方法将执行动画的对象和4个动画组合起来,还回的对象是ObjectAnimator,然后我们就可以通过 ObjectAnimator对象中的 start()方法来启动这个动画了。
我们是不是有这么一个疑惑?属性动画是通过改变对象的属性值来达到一个动画效果。那么这个对象的属性名称可以是什么呢?答案是:任何一切带有set开头的方法属性名字。可能我们常用的有:
透明度 alpha。
也就是说我们所有控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha()等方法。
我们不仅限于这几个属性,就拿TextView控件来说,只要是TextView有的属性都可以用来实现动画效果,比如 字体大小:“textColor”,字体颜色“textSize”等。
很多时候我们可能要在某一个动画执行之前 或者动画结束之后进行一些其他的操作,比如:动画结束之后进行网络数据请求等。那么我们就需要去获得该动画的一些状态,幸好,android系统给我们提供了一个动画监听器接口,来监听不同状态下的动画情况。实现也很简单,只要调用addListener(AnimatorListener listener)方法给动画添加监听器就好了,然后实现AnimatorListener接口即可。代码如下:
animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { //TODO 动画开始前的操作 /** * 比如这里可以初始化一些UI */ } @Override public void onAnimationEnd(Animator animation) { //TODO 动画结束的操作 /** * 比如这里可以等动画结束进行一些账号登录或者网络数据请求等。 */ } @Override public void onAnimationCancel(Animator animation) { //TODO 动画取消的操作 } @Override public void onAnimationRepeat(Animator animation) { //TODO 动画重复的操作 } });
可以根据不同需求来实现接口里面的四个方法。有时候你会觉得我不需要监听动画的四种状态,我只需要监听动画结束时候的状态,如果使用上面的方法就会感觉代码臃肿了,不过没关系,Android系统给我们提供了一个更好用的方法
animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { //TODO 动画结束的操作 /** * 比如这里可以等动画结束进行一些账号登录或者网络数据请求等。 */ } });
可以看出,我们使用了AnimatorListenerAdapter 动画接口适配器代替AnimatorListener接口。其实AnimatorListenerAdapter的源码只是一个实现了AnimatorListener接口的抽象类而已,你需要监听哪种动画状态就重写哪种方法就可以了。是不是觉得这个方法很nice~?如果你仅仅满足于这个那就OUT了,Android系统还给我们提供了一个更加精确的方法来时刻监听当前动画的执行情况。那就是addUpdateListener(AnimatorUpdateListener listener)方法了。调用该方法只需实现AnimatorUpdateListener接口就可以读取到动画的每个更新值了。来看看代码:
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); //可以根据自己的需要来获取动画更新值。 Log.e("TAG", "the animation value is " + value); } });
这个方法具体用在哪些地方可以参看上一节Android属性动画Property Animation系列一之ValueAnimator的动态的画一条斜线动画实现。
除了代码实现以上所有的动画,跟补间动画一样,Android系统也提供xml来实现属性动画。
相对于代码实现动画,xml可能显得麻烦些,不过xml动画可重复性好,编写一个xml动画可以多次使用。那么就来看看xml实现动画吧。和补间动画不同的是,在res目录下新建一个animator目录,补间动画是新建anim目录。在xml中实现动画会使用到如下三个标签
比如实现一个0?10的值的平滑过渡动画xml代码如下:
<?xml version="1.0" encoding="utf-8"?><animator xmlns:android="http://schemas.android.com/apk/res/android" android:valueFrom="0" android:valueTo="10" android:duration="2000" android:valueType="intType"></animator>
在比如实现一个从0旋转到90度的动画xml代码如下:
<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:propertyName="rotationX" android:valueFrom="0" android:valueTo="90" android:valueType="floatType" />
我们来个组合动画吧。
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:ordering="sequentially"><!--动画执行顺序 sequentially:顺序执行;together:同时执行。 --> <objectAnimator android:propertyName="translationX" android:valueFrom="0" android:valueTo="200" android:valueType="floatType" /> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:valueFrom="1" android:valueTo="2" android:valueType="floatType" /> <objectAnimator android:propertyName="rotationX" android:valueFrom="0" android:valueTo="90" android:valueType="floatType" /><!--动画值的类型--> </set></set>
xml动画写好了,接下来看看怎么在代码中调用它吧:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file); animator.setTarget(view); animator.start();
通过AnimatorInflater.loadAnimator方法加载xml动画返回一个Animator的对象,然后调用setTarget方法给动画设置对象调用哪个start启动动画即可完成xml动画效果啦。是不是也很简单呢?最后发现xml的动画可读性还是挺高的,点个赞~。
下一节我们继续学习 LayoutTransition:布局动画