Android种最常用的动画:
~1~Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果(旋转、平移、放缩和渐变)
Tweene Animations
主要类:
Animation 动画
AlphaAnimation 渐变透明度
RotateAnimation 画面旋转
ScaleAnimation 渐变尺寸缩放
TranslateAnimation 位置移动
AnimationSet 动画集
以自定义View为例,该View很简单,画面上只有一个图片。 现在我们要对整个View分别实现各种Tween动画效果。
AlphaAnimation
通过代码实现 AlphaAnimation,如下:
//初始化 Animation alphaAnimation = new AlphaAnimation(0.1f, 1.0f); //设置动画时间 alphaAnimation.setDuration(3000); this.startAnimation(alphaAnimation);
其中AlphaAnimation类第一个参数fromAlpha表示动画起始时的透明度, 第二个参数toAlpha表示动画结束时的透明度。
setDuration用来设置动画持续时间,setRepeatMode(Animation.REVERSE);使动画保存动画效果。
RotateAnimation
代码:
Animation rotateAnimation = new RotateAnimation(0f, 360f); rotateAnimation.setDuration(1000); this.startAnimation(rotateAnimation);
其中RotateAnimation类第一个参数fromDegrees表示动画起始时的角度, 第二个参数toDegrees表示动画结束时的角度。
另外还可以设置伸缩模式pivotXType、pivotYType, 伸缩动画相对于x,y 坐标的开始位置pivotXValue、pivotYValue等。
ScaleAnimation
代码:
//初始化 Animation scaleAnimation = new ScaleAnimation(0.1f, 1.0f,0.1f,1.0f); //设置动画时间 scaleAnimation.setDuration(500); this.startAnimation(scaleAnimation);
ScaleAnimation类中
第一个参数fromX ,第二个参数toX:分别是动画起始、结束时X坐标上的伸缩尺寸。
第三个参数fromY ,第四个参数toY:分别是动画起始、结束时Y坐标上的伸缩尺寸。
另外还可以设置伸缩模式pivotXType、pivotYType, 伸缩动画相对于x,y 坐标的开始位置pivotXValue、pivotYValue等。
TranslateAnimation
代码:
//初始化 Animation translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f); //设置动画时间 translateAnimation.setDuration(1000); this.startAnimation(translateAnimation);
TranslateAnimation类
第一个参数fromXDelta ,第二个参数toXDelta:分别是动画起始、结束时X坐标。
第三个参数fromYDelta ,第四个参数toYDelta:分别是动画起始、结束时Y坐标。
参数详细说明:
表二 |
||
XML节点 | 功能说明 | |
alpha | 渐变透明度动画效果 | |
<alpha android:fromAlpha=”0.1″ android:toAlpha=”1.0″ android:duration=”3000″ /> |
||
fromAlpha |
属性为动画起始时透明度 |
0.0表示完全透明 1.0表示完全不透明 以上值取0.0-1.0之间的float数据类型的数字 |
toAlpha | 属性为动画结束时透明度 |
表三 |
|||
scale | 渐变尺寸伸缩动画效果 | ||
<scale android:interpolator= “@android:anim/accelerate_decelerate_interpolator” android:fromXScale=”0.0″ android:toXScale=”1.4″ android:fromYScale=”0.0″ android:toYScale=”1.4″ android:pivotX=”50%” android:pivotY=”50%” android:fillAfter=”false” android:startOffset=“700” android:duration=”700″ android:repeatCount=”10″ /> |
|||
fromXScale[float] fromYScale[float] | 为动画起始时,X、Y坐标上的伸缩尺寸 | 0.0表示收缩到没有 1.0表示正常无伸缩 值小于1.0表示收缩 值大于1.0表示放大 |
|
toXScale [float] toYScale[float] |
为动画结束时,X、Y坐标上的伸缩尺寸 | ||
pivotX[float] pivotY[float] |
为动画相对于物件的X、Y坐标的开始位置 | 属性值说明:从0%-100%中取值,50%为物件的X或Y方向坐标上的中点位置 | |
表四 |
|||
translate | 画面转换位置移动动画效果 | ||
<translate android:fromXDelta=”30″ android:toXDelta=”-80″ android:fromYDelta=”30″ android:toYDelta=”300″ android:duration=”2000″ /> |
|||
fromXDelta toXDelta |
为动画、结束起始时 X坐标上的位置 | ||
fromYDelta toYDelta |
为动画、结束起始时 Y坐标上的位置 | ||
表五 |
|||
rotate | 画面转移旋转动画效果 | ||
<rotate android:interpolator=”@android:anim/accelerate_decelerate_interpolator” android:fromDegrees=”0″ android:toDegrees=”+350″ android:pivotX=”50%” android:pivotY=”50%” android:duration=”3000″ /> |
|||
fromDegrees | 为动画起始时物件的角度 | 说明 当角度为负数——表示逆时针旋转 当角度为正数——表示顺时针旋转 (负数from——to正数:顺时针旋转) (负数from——to负数:逆时针旋转) (正数from——to正数:顺时针旋转) (正数from——to负数:逆时针旋转) |
|
toDegrees | 属性为动画结束时物件旋转的角度 可以大于360度 | ||
pivotX pivotY |
为动画相对于物件的X、Y坐标的开始位 | 说明:以上两个属性值 从0%-100%中取值 50%为物件的X或Y方向坐标上的中点位置 |
|
以上都是单独的使用某个动画,那么如何让多个动画同时生效呢?
答案是 AnimationSet。
初看整个类名,还以为只是用来存放 Animation的一个Set, 细看才发现,该类也是继承自 Animation的。
下面我们实现一个动画,该动画会让图片移动的同时,图片透明度渐变
//初始化 Translate动画 translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f); //初始化 Alpha动画 alphaAnimation = new AlphaAnimation(0.1f, 1.0f); //动画集 AnimationSet set = new AnimationSet(true); set.addAnimation(translateAnimation); set.addAnimation(alphaAnimation); //设置动画时间 (作用到每个动画) set.setDuration(1000); this.startAnimation(set);
附上整个View类的代码吧。
import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; public class TweenAnim extends View { //Alpha动画 - 渐变透明度 private Animation alphaAnimation = null; //Sacle动画 - 渐变尺寸缩放 private Animation scaleAnimation = null; //Translate动画 - 位置移动 private Animation translateAnimation = null; //Rotate动画 - 画面旋转 private Animation rotateAnimation = null; public TweenAnim(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.e("Tween", "onDraw"); //加载一个图片 canvas.drawBitmap(((BitmapDrawable)getResources().getDrawable(R.drawable.gallery_photo_5)).getBitmap(), 0, 0, null); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.e("Tween", "onKeyDown"); return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { Log.e("Tween", "onKeyDown"); switch (keyCode) { case KeyEvent.KEYCODE_DPAD_UP: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_UP"); alphaAnimation = new AlphaAnimation(0.1f, 1.0f); //设置动画时间 alphaAnimation.setDuration(3000); this.startAnimation(alphaAnimation); break; case KeyEvent.KEYCODE_DPAD_DOWN: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_DOWN"); rotateAnimation = new RotateAnimation(0f, 360f); rotateAnimation.setDuration(1000); this.startAnimation(rotateAnimation); break; case KeyEvent.KEYCODE_DPAD_LEFT: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_LEFT"); //初始化 scaleAnimation = new ScaleAnimation(0.1f, 1.0f,0.1f,1.0f); //设置动画时间 scaleAnimation.setDuration(500); this.startAnimation(scaleAnimation); break; case KeyEvent.KEYCODE_DPAD_RIGHT: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_RIGHT"); //初始化 translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f); //设置动画时间 translateAnimation.setDuration(1000); this.startAnimation(translateAnimation); break; case KeyEvent.KEYCODE_DPAD_CENTER: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_CENTER"); //初始化 Translate动画 translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f); //初始化 Alpha动画 alphaAnimation = new AlphaAnimation(0.1f, 1.0f); //动画集 AnimationSet set = new AnimationSet(true); set.addAnimation(translateAnimation); set.addAnimation(alphaAnimation); //设置动画时间 (作用到每个动画) set.setDuration(1000); this.startAnimation(set); break; default: break; } return true; } } 在Activity中调用该类时,需要注意一定setFocusable(true), 否则焦点在Activity上的话,onKeyUp方法是不会生效的。 调用该View的代码: TweenAnim anim = new TweenAnim(Lesson_11.this); anim.setFocusable(true);
上面通过Java代码,实现了4中不同的Tween动画,其实在Android中完全可以通过 XML文件来实现动画。这种方式可能更加简洁、清晰,也更利于重用。
下面我们分别对这几种动画改用xml来实现。
首先是AlphaAnimation。
alpha_anim.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha="0.1" android:toAlpha="1.0" android:duration="2000" /> </set>
RotateAnimation
rotate_anim.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <rotate android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%" android:duration="500" /> </set>
ScaleAnimation
scale_anim.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXScale="0.0" android:toXScale="1.0" android:fromYScale="0.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:fillAfter="false" android:duration="500" /> </set>
TranslateAnimation
translate_anim.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="10" android:toXDelta="100" android:fromYDelta="10" android:toYDelta="100" /> </set>
需要用到AnimationUtils类。 通过该类中 loadAnimation 方法来加载这些布局文件。
如:
rotateAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.rotate_anim);
这次View类的代码如下:
import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; public class TweenAnim2 extends View { //Alpha动画 - 渐变透明度 private Animation alphaAnimation = null; //Sacle动画 - 渐变尺寸缩放 private Animation scaleAnimation = null; //Translate动画 - 位置移动 private Animation translateAnimation = null; //Rotate动画 - 画面旋转 private Animation rotateAnimation = null; public TweenAnim2(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.e("Tween", "onDraw"); //加载一个图片 canvas.drawBitmap(((BitmapDrawable)getResources().getDrawable(R.drawable.gallery_photo_5)).getBitmap(), 0, 0, null); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.e("Tween", "onKeyDown"); return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { Log.e("Tween", "onKeyDown"); switch (keyCode) { case KeyEvent.KEYCODE_DPAD_UP: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_UP"); alphaAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.alpha_anim); this.startAnimation(alphaAnimation); break; case KeyEvent.KEYCODE_DPAD_DOWN: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_DOWN"); rotateAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.rotate_anim); this.startAnimation(rotateAnimation); break; case KeyEvent.KEYCODE_DPAD_LEFT: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_LEFT"); scaleAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.scale_anim); this.startAnimation(scaleAnimation); break; case KeyEvent.KEYCODE_DPAD_RIGHT: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_RIGHT"); translateAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.translate_anim); this.startAnimation(translateAnimation); break; case KeyEvent.KEYCODE_DPAD_CENTER: Log.e("Tween", "onKeyDown - KEYCODE_DPAD_CENTER"); //初始化 Translate动画 translateAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.translate_anim); //初始化 Alpha动画 alphaAnimation = AnimationUtils.loadAnimation(this.getContext(), R.anim.alpha_anim); //动画集 AnimationSet set = new AnimationSet(true); set.addAnimation(translateAnimation); set.addAnimation(alphaAnimation); //设置动画时间 (作用到每个动画) set.setDuration(1000); this.startAnimation(set); break; default: break; } return true; } }
参考:::http://blog.csdn.net/feng88724/article/details/6318430
~2~Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似。帧动画
其实使用起来比较简单,首先需要创建一个AnimationDrawable对象,通过addFrame方法把每一帧要显示的内容添加进去,最后通过Start方法来播放动画。 同时还有设置循环setOneShot等方法可供使用。
下面先看一下官方对AnimationDrawable类的说明:
An object used to create frame-by-frame animations, defined by a series of Drawable objects, which can be used as a View object‘s background.
The simplest way to create a frame-by-frame animation is to define the animation in an XML file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
run()
to start the animation.An AnimationDrawable defined in XML consists of a single
<animation-list>
element, and a series of nested<item>
tags. Each item defines a frame of the animation. See the example below.spin_animation.xml file in res/drawable/ folder:
<!-- Animation frames are wheel0.png -- wheel5.png files inside the res/drawable/ folder --> <animation-list android: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>Here is the code to load and play this animation.
// 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()
新建一个AnimationDrawable对象,把这些图片加载进去。 addFrame第一参数表示要加载的内容,第二参数表示持续时间。
frameAnimation = new AnimationDrawable(); for (int i = 0; i < 10; i++) { int id = getResources().getIdentifier("load" + (i+1), "drawable", this.getContext().getPackageName()); frameAnimation.addFrame(getResources().getDrawable(id), 100); } //设置循环播放 false表示循环 true表示不循环,仅播放一次 frameAnimation.setOneShot(false);
AnimationDrawable 类是Drawable类的子类,因此可以将 AnimationDrawable 设为背景等来查看效果。最后只要调用 frameAnimation.start(); 就可以启动该Frame动画了。
那么上面是使用Java代码的方式来加载的Frame动画, 也可以像Tween动画那样,使用纯XML局部文件来做。 API中已经有说明,这边不再赘述了。
直接看示例:
<?xml version="1.0" encoding="utf-8"?> <animaltion-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/load1" android:duration="50" /> <item android:drawable="@drawable/load2" android:duration="50" /> <item android:drawable="@drawable/load3" android:duration="50" /> <item android:drawable="@drawable/load4" android:duration="50" /> <item android:drawable="@drawable/load5" android:duration="50" /> <item android:drawable="@drawable/load6" android:duration="50" /> <item android:drawable="@drawable/load7" android:duration="50" /> <item android:drawable="@drawable/load8" android:duration="50" /> <item android:drawable="@drawable/load9" android:duration="50" /> <item android:drawable="@drawable/load10" android:duration="50" /> </animaltion-list>
附上参数详细说明(来自: http://www.moandroid.com/?p=790)
表一 |
||
属性[类型] | 功能 | |
Duration[long] | 属性为动画持续时间 | 时间以毫秒为单位 |
fillAfter [boolean] | 当设置为true ,该动画转化在动画结束后被应用 | |
fillBefore[boolean] | 当设置为true ,该动画转化在动画开始前被应用 | |
interpolator |
指定一个动画的插入器 | 有一些常见的插入器 accelerate_decelerate_interpolator 加速-减速 动画插入器 accelerate_interpolator 加速-动画插入器 decelerate_interpolator 减速- 动画插入器 其他的属于特定的动画效果 |
repeatCount[int] | 动画的重复次数 | |
RepeatMode[int] | 定义重复的行为 | 1:重新开始 2:plays backward |
startOffset[long] | 动画之间的时间间隔,从上次动画停多少时间开始执行下个动画 | |
zAdjustment[int] | 定义动画的Z Order的改变 | 0:保持Z Order不变 1:保持在最上层 -1:保持在最下层 |
Android 属性动画:
Android提供了几种动画类型:View Animation 、Drawable Animation 、Property Animation 。View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。比如:你希望View有一个颜色的切换动画;你希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因.
相关API
Property Animation故名思议就是通过动画的方式改变对象的属性了,我们首先需要了解几个属性:
Duration动画的持续时间,默认300ms。
Time interpolation:时间差值,乍一看不知道是什么,但是我说LinearInterpolator、AccelerateDecelerateInterpolator,大家一定知道是干嘛的了,定义动画的变化率。
Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。
Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。
相关的类
ObjectAnimator 动画的执行类,后面详细介绍
ValueAnimator 动画的执行类,后面详细介绍
AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
AnimatorInflater 用户加载属性动画的xml文件
TypeEvaluator 类型估值,主要用于设置动画操作属性的值。
TimeInterpolator 时间插值,上面已经介绍。
总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。
ObjectAnimator实现动画
之所以选择ObjectAnimator为第一个~~是因为,这个实现最简单~~一行代码,秒秒钟实现动画,下面看个例子:
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_container" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/mv" android:scaleType="centerCrop" android:onClick="rotateyAnimRun" /> </RelativeLayout>
Activity代码:
package com.example.zhy_property_animation; import android.animation.ObjectAnimator; import android.app.Activity; import android.os.Bundle; import android.view.View; public class ObjectAnimActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.xml_for_anim); } public void rotateyAnimRun(View view) { ObjectAnimator// .ofFloat(view, "rotationX", 0.0F, 360.0F)// .setDuration(500)// .start(); } }
对于ObjectAnimator
1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。
当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~
动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~
2、如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。
对于ObjectAnimator 1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。 当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~ 动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~ 2、如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。
3、看了上面的例子,因为设置的操作的属性只有一个,那么如果我希望一个动画能够让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha),只使用ObjectAnimator咋弄?
想法是不是很不错,可能会说使用AnimatorSet啊,这一看就是一堆动画塞一起执行,但是我偏偏要用一个ObjectAnimator实例实现呢~下面看代码:
public void rotateyAnimRun(final View view) { ObjectAnimator anim = ObjectAnimator// .ofFloat(view, "zhy", 1.0F, 0.0F)// .setDuration(500);// anim.start(); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); view.setAlpha(cVal); view.setScaleX(cVal); view.setScaleY(cVal); } }); }
把设置属性的那个字符串,随便写一个该对象没有的属性,就是不管~~咱们只需要它按照时间插值和持续时间计算的那个值,我们自己手动调用~
这个例子就是想说明一下,有时候换个思路不要被API所约束,利用部分API提供的功能也能实现好玩的效果~~~
比如:你想实现抛物线的效果,水平方向100px/s,垂直方向加速度200px/s*s ,咋实现呢~~可以自己用ObjectAnimator试试~
4、其实还有更简单的方式,实现一个动画更改多个效果:使用propertyValuesHolder
public void propertyValuesHolder(View view) { PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start(); }
监听动画的事件
对于动画,一般都是一些辅助效果,比如我要删除个元素,我可能希望是个淡出的效果,但是最终还是要删掉,并不是你透明度没有了,还占着位置,所以我们需要知道动画如何结束。
所以我们可以添加一个动画的监听:
public void fadeOut(View view) { ObjectAnimator anim = ObjectAnimator.ofFloat(mBlueBall, "alpha", 0.5f); anim.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Log.e(TAG, "onAnimationStart"); } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub Log.e(TAG, "onAnimationRepeat"); } @Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); ViewGroup parent = (ViewGroup) mBlueBall.getParent(); if (parent != null) parent.removeView(mBlueBall); } @Override public void onAnimationCancel(Animator animation) { // TODO Auto-generated method stub Log.e(TAG, "onAnimationCancel"); } }); anim.start(); }
这样就可以监听动画的开始、结束、被取消、重复等事件~但是有时候会觉得,我只要知道结束就行了,这么长的代码我不能接收,那你可以使用AnimatorListenerAdapter
anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { Log.e(TAG, "onAnimationEnd"); ViewGroup parent = (ViewGroup) mBlueBall.getParent(); if (parent != null) parent.removeView(mBlueBall); } });
AnimatorSet的使用
实例:
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_container" > <ImageView android:id="@+id/id_ball" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/bol_blue" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="togetherRun" android:text="简单的多动画Together" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="playWithAfter" android:text="多动画按次序执行" /> </LinearLayout> </RelativeLayout>
代码:
package com.example.zhy_property_animation; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; public class AnimatorSetActivity extends Activity { private ImageView mBlueBall; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.anim_set); mBlueBall = (ImageView) findViewById(R.id.id_ball); } public void togetherRun(View view) { ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f); AnimatorSet animSet = new AnimatorSet(); animSet.setDuration(2000); animSet.setInterpolator(new LinearInterpolator()); //两个动画同时执行 animSet.playTogether(anim1, anim2); animSet.start(); } public void playWithAfter(View view) { float cx = mBlueBall.getX(); ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f); ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f); ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall, "x", cx , 0f); ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall, "x", cx); /** * anim1,anim2,anim3同时执行 * anim4接着执行 */ AnimatorSet animSet = new AnimatorSet(); animSet.play(anim1).with(anim2); animSet.play(anim2).with(anim3); animSet.play(anim4).after(anim3); animSet.setDuration(1000); animSet.start(); } }
写了两个效果:
第一:使用playTogether两个动画同时执行,当然还有playSequentially依次执行~~
第二:如果我们有一堆动画,如何使用代码控制顺序,比如1,2同时;3在2后面;4在1之前等~就是效果2了
有一点注意:animSet.play().with();也是支持链式编程的,但是不要想着狂点,比如 animSet.play(anim1).with(anim2).before(anim3).before(anim5); 这样是不行的,系统不会根据你写的这一长串来决定先后的顺序,所以麻烦你按照上面例子的写法,多写几行:
1、如何使用xml文件来创建属性动画
大家肯定都清楚,View Animator 、Drawable Animator都可以在anim文件夹下创建动画,然后在程序中使用,甚至在Theme中设置为属性值。当然了,属性动画其实也可以在文件中声明:
首先在res下建立animator文件夹,然后建立res/animator/scalex.xml
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="2.0" android:valueType="floatType" > </objectAnimator>
代码:
public void scaleX(View view) { // 加载动画 Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex); anim.setTarget(mMv); anim.start(); }
使用AnimatorInflater加载动画的资源文件,然后设置目标,就ok~~是不是很简单,这只是单纯横向的放大一倍~
如果我希望纵向与横向同时缩放呢?则可以怎么定义属性文件:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" > <objectAnimator android:duration="1000" android:propertyName="scaleX" android:valueFrom="1" android:valueTo="0.5" > </objectAnimator> <objectAnimator android:duration="1000" android:propertyName="scaleY" android:valueFrom="1" android:valueTo="0.5" > </objectAnimator> </set>
使用set标签,有一个orderring属性设置为together,【还有另一个值:sequentially(表示一个接一个执行)】。
上篇博客中忽略了一个效果,就是缩放、反转等都有中心点或者轴,默认中心缩放,和中间对称线为反转线,所以我决定这个横向,纵向缩小以左上角为中心点:
代码:
// 加载动画 Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale); mMv.setPivotX(0); mMv.setPivotY(0); //显示的调用invalidate mMv.invalidate(); anim.setTarget(mMv); anim.start();
2、布局动画(Layout Animations)
主要使用LayoutTransition为布局的容器设置动画,当容器中的视图层次发生变化时存在过渡的动画效果。
基本代码为:
LayoutTransition transition = new LayoutTransition(); transition.setAnimator(LayoutTransition.CHANGE_APPEARING, transition.getAnimator(LayoutTransition.CHANGE_APPEARING)); transition.setAnimator(LayoutTransition.APPEARING, null); transition.setAnimator(LayoutTransition.DISAPPEARING, null); transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, null); mGridLayout.setLayoutTransition(transition);
过渡的类型一共有四种:
LayoutTransition.APPEARING 当一个View在ViewGroup中出现时,对此View设置的动画
LayoutTransition.CHANGE_APPEARING 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画
LayoutTransition.DISAPPEARING 当一个View在ViewGroup中消失时,对此View设置的动画
LayoutTransition.CHANGE_DISAPPEARING 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画
LayoutTransition.CHANGE 不是由于View出现或消失造成对其他View位置造成影响,然后对其他View设置的动画。
注意动画到底设置在谁身上,此View还是其他View。
好了下面看一个综合的例子:
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/id_container" 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="addBtn" android:text="addBtns" /> <CheckBox android:id="@+id/id_appear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="APPEARING" /> <CheckBox android:id="@+id/id_change_appear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="CHANGE_APPEARING" /> <CheckBox android:id="@+id/id_disappear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="DISAPPEARING" /> <CheckBox android:id="@+id/id_change_disappear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="CHANGE_DISAPPEARING " /> </LinearLayout>
代码:
package com.example.zhy_property_animation; import android.animation.LayoutTransition; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.GridLayout; public class LayoutAnimaActivity extends Activity implements OnCheckedChangeListener { private ViewGroup viewGroup; private GridLayout mGridLayout; private int mVal; private LayoutTransition mTransition; private CheckBox mAppear, mChangeAppear, mDisAppear, mChangeDisAppear; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_animator); viewGroup = (ViewGroup) findViewById(R.id.id_container); mAppear = (CheckBox) findViewById(R.id.id_appear); mChangeAppear = (CheckBox) findViewById(R.id.id_change_appear); mDisAppear = (CheckBox) findViewById(R.id.id_disappear); mChangeDisAppear = (CheckBox) findViewById(R.id.id_change_disappear); mAppear.setOnCheckedChangeListener(this); mChangeAppear.setOnCheckedChangeListener(this); mDisAppear.setOnCheckedChangeListener(this); mChangeDisAppear.setOnCheckedChangeListener(this); // 创建一个GridLayout mGridLayout = new GridLayout(this); // 设置每列5个按钮 mGridLayout.setColumnCount(5); // 添加到布局中 viewGroup.addView(mGridLayout); //默认动画全部开启 mTransition = new LayoutTransition(); mGridLayout.setLayoutTransition(mTransition); } /** * 添加按钮 * * @param view */ public void addBtn(View view) { final Button button = new Button(this); button.setText((++mVal) + ""); mGridLayout.addView(button, Math.min(1, mGridLayout.getChildCount())); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mGridLayout.removeView(button); } }); } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mTransition = new LayoutTransition(); mTransition.setAnimator( LayoutTransition.APPEARING, (mAppear.isChecked() ? mTransition .getAnimator(LayoutTransition.APPEARING) : null)); mTransition .setAnimator( LayoutTransition.CHANGE_APPEARING, (mChangeAppear.isChecked() ? mTransition .getAnimator(LayoutTransition.CHANGE_APPEARING) : null)); mTransition.setAnimator( LayoutTransition.DISAPPEARING, (mDisAppear.isChecked() ? mTransition .getAnimator(LayoutTransition.DISAPPEARING) : null)); mTransition.setAnimator( LayoutTransition.CHANGE_DISAPPEARING, (mChangeDisAppear.isChecked() ? mTransition .getAnimator(LayoutTransition.CHANGE_DISAPPEARING) : null)); mGridLayout.setLayoutTransition(mTransition); } }
参考:http://blog.csdn.net/lmj623565791/article/details/38092093