2.3以及以前的版本支持3种类型的动画:逐帧动画,布局动画,视图动画。布局动画,视图动画合称为补间动画。
3.0后推出了属性动画
一.逐帧动画
逐帧动画就像动画片一样把一些图片组合并且快速播放,好像物体在运动一样。
创建逐帧动画,使用AnimationDrawable这个类
显示动画的步骤:
1.在布局文件中加入imageview用于显示动画
2.准备一些连续播放起来可以形成“动画”的图片,且称为帧图片,然后构造一个xml来声明这些帧图片
loading.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <animation-list android:oneshot="false"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:duration="100" android:drawable="@drawable/loading_00" />
- <item android:duration="100" android:drawable="@drawable/loading_01" />
- <item android:duration="100" android:drawable="@drawable/loading_02" />
- <item android:duration="100" android:drawable="@drawable/loading_03" />
- <item android:duration="100" android:drawable="@drawable/loading_04" />
- <item android:duration="100" android:drawable="@drawable/loading_05" />
- <item android:duration="100" android:drawable="@drawable/loading_06" />
- <item android:duration="100" android:drawable="@drawable/loading_07" />
- </animation-list>
android:oneshot="false"表明动画连续播放,android:duration表明持续时间100毫秒
3.代码中设置动画
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Button start = (Button) findViewById(R.id.start);
- ImageView imgView = (ImageView)findViewById(R.id.img);
- imgView.setBackgroundResource(R.anim.loading);
- final AnimationDrawable frameAnimation =
- (AnimationDrawable) imgView.getBackground();
- start.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (frameAnimation.isRunning()) {
- //动画暂停
- frameAnimation.stop();
- }
- else {
- //动画启动
- frameAnimation.start();
- }
- }
- });
- }
- }
以上转动效果还可以用progressbar实现
- <ProgressBar
- android:id="@+id/progress"
- android:layout_width="20dp"
- android:layout_height="20dp"
- android:indeterminateDrawable="@anim/loading" />
二.补间动画(布局动画,视图动画)
补间动画的类型:
缩放动画:沿x轴或者y轴缩小或者放大视图,也可以指定一个支点并围绕该支点来缩放动画
旋转动画:围绕一个支点将视图旋转一定角度
平移动画:沿x或者y轴移动视图
透明度动画:更改视图的透明度
(1).布局动画
布局动画作用于ViewGroup的子节点(LinearLayout下的view,或者ListVIew, GridView等的item),为什么叫布局动画,大概是因为在布局文件中实现吧
这里演示如何在xml文件中创建,下面提到的xml文件都放在anim文件夹下。步骤如下:
1.创建动画的xml文件,节点名称根据你想要的效果(缩放,旋转,平移,透明度)而选择
缩放动画scale.xml:
- <scale
- android:fromXScale="1"
- android:toXScale="1"
- android:fromYScale="0.1"
- android:toYScale="1.0"
- android:duration="500"
- android:pivotX="50%"
- android:pivotY="50%"
- android:startOffset="100" />
属性说明:
android:fromXScale="1"
android:toXScale="1"指定在x轴上的放大系数变化值,从1到1表明不变,y轴同理
android:duration="500" 缩放时间500毫秒
android:pivotX="50%"
android:pivotY="50%"
在中间时刻,对象在x,y方向上都为50%
android:startOffset="100" 在动画开始前等待100毫秒
旋转动画rotate.xml:
- <rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/accelerate_interpolator"
- android:fromDegrees="0.0"
- android:toDegrees="360"
- android:pivotX="50%"
- android:pivotY="50%"
- android:duration="500" />
属性说明:角度从0到360度旋转,中间时刻旋转一半角度,一次旋转时间500毫秒
android:interpolator="@android:anim/accelerate_interpolator"
指定动画所用的插值器是系统自带的加速插值器,插值器指定了动画的某个属性,比如角度如何随时间变化,是否是匀速旋转,还是越转越快?这里是越转越快
平移动画translate.xml:
- <translate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromYDelta="-100%" android:toYDelta="0"
- android:duration="500" />
属性说明:从上往下进入屏幕,平移动画具体说明可以参考这个文章:
透明度动画alpha.xml:
- <alpha xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="1000"
- android:fromAlpha="0.0"
- android:interpolator="@android:anim/accelerate_interpolator"
- android:toAlpha="1.0" />
属性说明:透明度从0到1,渐变持续1秒
2.amin文件夹下创建xml,节点名称为layoutAnimation,属性中声明使用的动画:
layout_controller.xml
- <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
- android:delay="30%"
- android:animationOrder="reverse"
- android:animation="@anim/rotate"
- />
android:animation="@anim/rotate,此布局动画使用了旋转动画
3.在主页面布局中引用此布局动画的xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layoutAnimation="@anim/layout_controller"
- >
- <TextView
- android:id="@+id/list_view_id"
- android:text="sadas"
- android:textSize="40sp"
- android:gravity="center"
- android:layout_gravity="center"
- android:persistentDrawingCache="animation|scrolling"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
android:layoutAnimation="@anim/layout_controller声明了上面的layout_controller.xml。现在运行程序,可以看到textview载入的时候运行了旋转的动画
android:persistentDrawingCache="animation|scrolling 可以提高效率
动画之间还可以组合,相当于把动画元素放入集合类中,像这样:
- <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator">
- <translate android:fromYDelta="-100%" android:toYDelta="0" android:duration="500" />
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="500" />
- </set>
引用它的xml:
- <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
- android:delay="30%"
- android:animationOrder="reverse"
- android:animation="@anim/alpha_translate"
- />
要使得2个Activity切换时播放动画,可以套用以上几种类型的动画xml,最后在代码中加上这句代码就行。
- startActivity(intent);
- //第一个参数为启动时动画效果,第二个参数为退出时动画效果
- overridePendingTransition(R.anim.fade, R.anim.hold);
(2)视图动画
布局动画实现的效果视图动画都可以实现,视图动画使用纯代码制作动画,可以完成比布局动画更复杂的效果(矩阵变换等),但是实现复杂度也更大。
先看一个简单的实现,2个步骤,
1.实现动画类ViewAnimation2,设置动画的形式
2.调用布局总view的startAnimation方法将此动画设置给view。
activity:
- public class ViewAnimationActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.list_layout);
- setupListView();
- this.setupButton();
- }
- private void setupListView()
- {
- String[] listItems = new String[] {
- "Item 1", "Item 2", "Item 3",
- "Item 4", "Item 5", "Item 6",
- };
- ArrayAdapter<String> listItemAdapter =
- new ArrayAdapter<String>(this
- ,android.R.layout.simple_list_item_1
- ,listItems);
- ListView lv = (ListView)this.findViewById(R.id.list_view_id);
- lv.setAdapter(listItemAdapter);
- }
- private void setupButton()
- {
- Button b = (Button)this.findViewById(R.id.btn_animate);
- b.setOnClickListener(
- new Button.OnClickListener(){
- public void onClick(View v)
- {
- animateListView();
- }
- });
- }
- private void animateListView()
- {
- ListView lv = (ListView)this.findViewById(R.id.list_view_id);
- lv.startAnimation(new ViewAnimation2());
- }
- }
动画实现 ViewAnimation2:
- public class ViewAnimation2 extends Animation
- {
- public ViewAnimation2(){}
- @Override
- public void initialize(int width, int height, int parentWidth, int parentHeight) {
- super.initialize(width, height, parentWidth, parentHeight);
- setDuration(2500);
- setFillAfter(true);
- setInterpolator(new LinearInterpolator());
- }
- //interpolatedTime值从0到1
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- final Matrix matrix = t.getMatrix();
- matrix.setScale(interpolatedTime, interpolatedTime);
- }
- }
initialize方法是初始化时的回调方法,设置动画的一些属性(持续时间,插值器等)
applyTransformation方法在动画执行的过程中被反复调用,android反复调用这个方法来模拟动画,interpolatedTime参数根据initialize方法中设置的时间,从0到1变化,每次回调时的值都不同。当interpolatedTime值增长到1时,动画播放结束。可以利用applyTransformation这个方法进行对象的矩阵变换,以形成动画。以上的例子是根据时间逐渐增长listview的大小。
setInterpolator(new LinearInterpolator())指定动画匀速运行,matrix.setScale(interpolatedTime, interpolatedTime)让view的大小随时间增长变大。
稍微改进一下上面的动画:
- public class ViewAnimationActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.list_layout);
- setupListView();
- this.setupButton();
- }
- private void setupListView()
- {
- String[] listItems = new String[] {
- "Item 1", "Item 2", "Item 3",
- "Item 4", "Item 5", "Item 6",
- };
- ArrayAdapter<String> listItemAdapter =
- new ArrayAdapter<String>(this
- ,android.R.layout.simple_list_item_1
- ,listItems);
- ListView lv = (ListView)this.findViewById(R.id.list_view_id);
- lv.setAdapter(listItemAdapter);
- }
- private void setupButton()
- {
- Button b = (Button)this.findViewById(R.id.btn_animate);
- b.setOnClickListener(
- new Button.OnClickListener(){
- public void onClick(View v)
- {
- animateListView();
- }
- });
- }
- private void animateListView()
- {
- ListView lv = (ListView)this.findViewById(R.id.list_view_id);
- float currX = (float) (lv.getHeight() / 2.0);
- float currY = (float) (lv.getWidth() / 2.0);
- // lv.startAnimation(new ViewAnimation2());
- lv.startAnimation(new ViewAnimation(currX, currY));
- }
- public class ViewAnimation extends Animation {
- float centerX, centerY;
- public ViewAnimation(float cx, float cy)
- {
- centerX = cx;
- centerY = cy;
- }
- @Override
- public void initialize(int width, int height, int parentWidth, int parentHeight) {
- super.initialize(width, height, parentWidth, parentHeight);
- setDuration(2500);
- setFillAfter(true);
- setInterpolator(new LinearInterpolator());
- }
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- applyTransformationNew(interpolatedTime,t);
- }
- protected void applyTransformationNew(float interpolatedTime, Transformation t)
- {
- final Matrix matrix = t.getMatrix();
- matrix.setScale(interpolatedTime, interpolatedTime);
- matrix.preTranslate(-centerX, -centerY);
- matrix.postTranslate(centerX, centerY);
- }
- }
注意到applyTransformationNew方法中多了preTranslate和postTranslate,相当于在动画缩放前后进行了位置平移。
视图动画其他更丰富的实现效果有待深入研究。
三.属性动画
旧的动画API位于包android.view.animation中,新的动画API位于包android.animation中
属性动画主要有以下一些特性
ValueAnimator 值动画生成器
ObjectAnimator 对象动画生成器ViewPropertyAnimator 视图属性动画生成器AnimatorSet 动画生成器集合Animation Listeners 动画生成器监听TypeEvaluator 类型求值器PropertyValuesHolder 属性值持有者Interpolators 插值器Keyframes 关键帧Layout Changes 布局转变Declaring Animations in XML xml加载动画
1.ValueAnimator 值动画生成器
ValueAnimator持续跟踪动画的状态,比如动画运行时间和某个属性的值,它包含一个时间插值器TimeInterpolator,定义了动画的插值器。还包含一个类型求值器TypeEvaluator ,定义了如何计算动画的属性值。比如在下图中,view的坐标随着时间的增加而以整数增加,并且是加速增长的,在这个动画中,插值器是AccelerateDecelerateInterpolator,类型求值器是IntEvaluator
看一下API GUIDE上给出的示意图:
对应的代码以及解释:
- ValueAnimator anim = ValueAnimator.ofInt(10, 200);
- anim.setDuration(5000);
- anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- // TODO Auto-generated method stub
- int value = (Integer) animation.getAnimatedValue();
- }
- });
- anim.start();
ValueAnimator的实例设置持续时间duration,开始,结束值startPropertyValue和endPropertyValue,ValueAnimator.AnimatorUpdateListener监听属性值的变化,onAnimationUpdate方法在动画执行过程中不断被回调,animation.getAnimatedValue获得某个时间点上的属性值
- ObjectAnimator fadeOut =
- ObjectAnimator.ofFloat(tv, "alpha", 0f, 100f);
- fadeOut.setDuration(5000);
- fadeOut.start();
其中tv是个textview实例,alpha是属性,这个属性不是随便设置的,是因为textview中存在setAlpha这个方法(继承自view),如果你给这个参数指定了一个值,那么实现动画的对象中必须存在对应的set的方法。可以传入的参数有:
translationX
translationYrotationrotationXrotationYscaleXscaleYpivotXpivotYx yalpha3.AnimatorSet 动画生成器集合
AnimatorSet可以把多个动画组合在一起,并且决定他们的播放顺序
textview先淡出再淡入的效果:
- m_tv.setAlpha(1f);
- ObjectAnimator fadeOut =
- ObjectAnimator.ofFloat(tv, "alpha", 0f);
- ObjectAnimator fadeIn =
- ObjectAnimator.ofFloat(tv, "alpha", 1f);
- AnimatorSet as = new AnimatorSet();
- as.playSequentially(fadeOut,fadeIn);
- as.setDuration(5000);
- as.start();
这里new 了一个AnimatorSet对象,并且将2个ObjectAnimator对象当作参数传入playSequentially方法,使它们顺序执行
API GUIDE上的一个例子:
- AnimatorSet bouncer = new AnimatorSet();
- bouncer.play(bounceAnim).before(squashAnim1);
- bouncer.play(squashAnim1).with(squashAnim2);
- bouncer.play(squashAnim1).with(stretchAnim1);
- bouncer.play(squashAnim1).with(stretchAnim2);
- bouncer.play(bounceBackAnim).after(stretchAnim2);
- ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
- fadeAnim.setDuration(250);
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.play(bouncer).before(fadeAnim);
- animatorSet.start();
这段代码的作用是先后播放2个AnimatorSet,播放的动画顺序是bounceAnim->squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2(同时)->bounceBackAnim->fadeAnim
4.ViewPropertyAnimator视图属性动画生成器
ViewPropertyAnimator有些类似于AnimatorSet,它提供了更简便的方法在动画中同时改变view的属性
下面的代码作用是把textview 从屏幕的右下角移动到原来的位置
- m_tv.setAlpha(1f);
- float h = m_tv.getHeight();
- float w = m_tv.getWidth();
- float x = m_tv.getX();
- float y = m_tv.getY();
- m_tv.setX(w);
- m_tv.setY(h);
- ViewGroup layout = (ViewGroup)m_tv.getParent();
- layout.setClipChildren(true);
- ViewPropertyAnimator vpa = m_tv.animate();
- vpa.x(x);
- vpa.y(y);
- vpa.setDuration(5000);
- vpa.setInterpolator(
- new AccelerateDecelerateInterpolator());
5.动画监听Animation Listeners
Animator.AnimatorListener 监听开始,结束,重复,退出等事件
ValueAnimator.AnimatorUpdateListener 在上面ValueAnimator的例子中演示过,在动画执行过程中不断回调,可以监听动画属性值的变化
6.TypeEvaluator 类型求值器Animator提供ofInt,ofFloat来设置动画属性的变化范围,如果想实现自己的变化,可以实现TypeEvaluator接口
- public class FloatEvaluator implements TypeEvaluator {
- public Object evaluate(float fraction, Object startValue, Object endValue) {
- float startFloat = ((Number) startValue).floatValue();
- return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
- }
- }
7.PropertyValuesHolder 属性值持有者
PropertyValuesHolder用来在动画中保存一个或者多个view的属性名/目标值,用来生成动画。以下的代码和上面ViewPropertyAnimator的例子实现的是一样的动画效果
- m_tv.setAlpha(1f);
- float h = m_tv.getHeight();
- float w = m_tv.getWidth();
- float x = m_tv.getX();
- float y = m_tv.getY();
- m_tv.setX(w);
- m_tv.setY(h);
- PropertyValuesHolder pvhX =
- PropertyValuesHolder.ofFloat("x", x);
- PropertyValuesHolder pvhY =
- PropertyValuesHolder.ofFloat("y", y);
- ObjectAnimator oa
- = ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhX, pvhY);
- oa.setDuration(5000);
- oa.setInterpolator(
- new AccelerateDecelerateInterpolator());
- oa.start();
8.Keyframes 关键帧
Keyframes由时间/值的键值对组成,顾名思义,就是指定动画一些关键时间点上的属性值,它可以和PropertyValuesHolder配合使用
下面的代码作用是,动画运行时,textview从右下移动到左上,当时间到达20%时,透明度变为80%,一半时间时,透明度变为20%,到80%的时间时,透明度变回80%
- m_tv.setAlpha(1f);
- float h = m_tv.getHeight();
- float w = m_tv.getWidth();
- float x = m_tv.getX();
- float y = m_tv.getY();
- //3个时间点不同的透明度设置
- Keyframe kf0 = Keyframe.ofFloat(0.2f, 0.8f);
- Keyframe kf1 = Keyframe.ofFloat(.5f, 0.2f);
- Keyframe kf2 = Keyframe.ofFloat(0.8f, 0.8f);
- PropertyValuesHolder pvhAlpha =
- PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2);
- PropertyValuesHolder pvhX =
- PropertyValuesHolder.ofFloat("x", w, x);
- //end frame
- ObjectAnimator anim =
- ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhAlpha,pvhX);
- anim.setDuration(5000);
- anim.start();
9.Layout Changes 布局转变
属性动画的API可以在ViewGroup上设置动画,系统为ViewGroup的子view的显示和消失都设置了默认的动画,要启用它们只要在xml文件中加上
- android:animateLayoutChanges="true"
下面代码展示了gridlayout中按钮增加/删除的默认动画
- public class MainActivity extends Activity {
- private int numButtons = 1;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.layout_animations_by_default);
- final GridLayout gridContainer = (GridLayout) findViewById(R.id.gridContainer);
- Button addButton = (Button) findViewById(R.id.addNewButton);
- addButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Button newButton = new Button(MainActivity.this);
- newButton.setText(String.valueOf(numButtons++));
- newButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- gridContainer.removeView(v);
- }
- });
- gridContainer.addView(newButton, Math.min(1, gridContainer.getChildCount()));
- }
- });
- }
- }
布局:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Add Button"
- android:id="@+id/addNewButton"
- />
- <GridLayout
- android:columnCount="4"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/gridContainer"
- android:animateLayoutChanges="true"
- />
- </LinearLayout>
也可以自己设置相应的效果:
- LinearLayout yourLayout = (LinearLayout)findViewById(R.layout.xx);
- LayoutTransition lt = new LayoutTransition();
- yourLayout.setLayoutTransition(lt);
- Animator a = lt.getAnimator(LayoutTransition.APPEARING);
- ObjectAnimator oa = ..... //自定义的ObjectAnimator
- lt.setAnimator(LayoutTransition.APPEARING, oa);
10.Declaring Animations in XML 在xml中定义动画
属性动画也可以用xml定义动画,但是xml文件不是放在res/anim下,而是放在res/animator下
标签对应的动画类:
ValueAnimator - <animator>
ObjectAnimator - <objectAnimator>AnimatorSet - <set>
- <set android:ordering="sequentially">
- <set>
- <objectAnimator
- android:propertyName="x"
- android:duration="500"
- android:valueTo="400"
- android:valueType="intType"/>
- <objectAnimator
- android:propertyName="y"
- android:duration="500"
- android:valueTo="300"
- android:valueType="intType"/>
- </set>
- <objectAnimator
- android:propertyName="alpha"
- android:duration="500"
- android:valueTo="1f"/>
- </set>
要使xml定义的动画生效,需要加上以下代码:
- AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
- R.anim.property_animator);
- set.setTarget(myObject);
- set.start();
参考资料:
感谢 : http://blog.csdn.net/ohehehou/article/details/12144693