属性动画、帧动画、补间动画的介绍使用及对比

属性动画、帧动画、补间动画的介绍使用及对比

版权声明:转载必须注明本文转自南轩的博客: http://blog.csdn.net/nanxuan521

在android开发中经常会碰到一些动画需求,其中一部分动画依靠android SDK中自带的动画就可以实行,在5.0以后安卓系统多了很多动画,比如跳转,关闭。。。等等很多动画,让我们的APP在使用中不在那么生硬,用起来更加的舒服,说白了就是用户体验更好了,那么今天给大家讲讲目前Android的动画都有哪些,他们的区别是什么,以后哪一种动画更炫酷一些。

补间动画(Tween Animation)

1、补间动画的特性:

  • a.渐变动画支持四种类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度

  • b. 只是显示的位置变动,View的实际位置未改变,表现为View移动到其他地方,点击事件仍在原处才能响应。

  • c. 组合使用步骤较复杂。

  • d. View Animation 也是指此动画。

2、补间动画的优缺点:

  • 缺点:当平移动画执行完停在最后的位置,结果焦点还在原来的位置(控件的属性没有真的被改变)
  • 优点:相对于逐帧动画来说,补间动画更为连贯自然

3、补间动画的实现:

首先要准备你的补间动画的代码将他放在资源文件夹下的anim文件夹里,就以平移,翻转、缩放、透明动画为例:
透明补间动画:

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:fillAfter="true"
    >
    <alpha
        android:duration="2000"
        android:fromAlpha="1"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:toAlpha="0" />
set>

旋转补间动画:

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:fillAfter="true"
    >
       <rotate
        android:duration="2000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="720" >
    rotate>

    <rotate
        android:duration="2000"
        android:fromDegrees="360"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="2000"
        android:toDegrees="0" >
    rotate>
set>

缩放补间动画:

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:fillAfter="true"
    >
      <scale android:fromXScale="1"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:fromYScale="1"
        android:toXScale="2.0"
        android:toYScale="2.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="true"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:duration="2000"/>
set>

移动补间动画:

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:fillAfter="true"
    >
      <translate
        android:fromXDelta="0"
        android:toXDelta="860"
        android:fromYDelta="0"
        android:toYDelta="0"
        android:fillAfter="true"
        android:repeatMode="reverse"
        android:repeatCount="1"
        android:duration="2000">
    translate>
set>

下面就是在需要展示动画的时候调用了:

/**
 * 补间动画
 *
 * @author wangyangke
 * @date:2016.9.1 @time 23:40
 */
public class TweenActivity extends AppCompatActivity {
    private Button b1, b2, b3, b4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tween);
        final Animation rotate = AnimationUtils.loadAnimation(this,
                R.anim.anim_rotate);
        final Animation translate = AnimationUtils.loadAnimation(this,
                R.anim.anim_translate);
        final Animation scale = AnimationUtils.loadAnimation(this,
                R.anim.anim_scale);
        final Animation alpha = AnimationUtils.loadAnimation(this,
                R.anim.anim_alpha);
        final ImageView iv = (ImageView) findViewById(R.id.imageview);

        b1 = (Button) findViewById(R.id.btnAlpha);

        b2 = (Button) findViewById(R.id.btnRotate);

        b3 = (Button) findViewById(R.id.btnScale);

        b4 = (Button) findViewById(R.id.btnTranslate);

        b1.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                iv.startAnimation(alpha);

            }
        });
        b2.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                iv.startAnimation(rotate);
            }
        });
        b3.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                iv.startAnimation(scale);
            }
        });
        b4.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                iv.startAnimation(translate);
            }
        });
    }

    public void mToast(View iv) {
        Toast.makeText(this, "图片被点击了!", Toast.LENGTH_SHORT).show();
    }
}

帧动画(Frame Animation)

1、帧动画的特性:

  • a. 用于生成连续的Gif效果图。

  • b. DrawableAnimation也是指此动画

2、帧动画的优缺点:

  • 缺点:效果单一,逐帧播放需要很多图片,占用控件较大
  • 优点:制作简单

3、帧动画的实现:

帧动画的效果很单一,当然实现方法也很简单,效果就是达到了GIF图和flansh的效果:


<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true">
    <item android:drawable="@drawable/f1" android:duration="300" />
    <item android:drawable="@drawable/f2" android:duration="300" />
    <item android:drawable="@drawable/f3" android:duration="300" />
    <item android:drawable="@drawable/f4" android:duration="300" />
    <item android:drawable="@drawable/f5" android:duration="300" />
    <item android:drawable="@drawable/f6" android:duration="300" />
    <item android:drawable="@drawable/f7" android:duration="300" />
    <item android:drawable="@drawable/f6" android:duration="300" />
    <item android:drawable="@drawable/f5" android:duration="300" />
    <item android:drawable="@drawable/f4" android:duration="300" />
    <item android:drawable="@drawable/f4" android:duration="300" />
    <item android:drawable="@drawable/f3" android:duration="300" />
    <item android:drawable="@drawable/f2" android:duration="300" />
    <item android:drawable="@drawable/f7" android:duration="300" />
animation-list>

使用:

/**
 * 帧动画
 *
 * @author wangyangke
 * @date:2016.9.1 @time 23:50
 */
public class FrameActivity extends AppCompatActivity {
    private ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame);
        image = (ImageView) findViewById(R.id.frame_image);

    }


    public void startFrame(View view) {
        image.setBackgroundResource(R.anim.anim_frame);
        AnimationDrawable anim = (AnimationDrawable) image.getBackground();
        anim.start();
    }
    public void stopFrame(View view) {
        AnimationDrawable anim = (AnimationDrawable) image.getBackground();
        if (anim.isRunning()) { //如果正在运行,就停止
            anim.stop();
        }
    }
    public void startFrame1(View view) {
        image.setBackgroundResource(R.anim.anim_frame1);
        AnimationDrawable anim = (AnimationDrawable) image.getBackground();
        anim.start();
    }
}

属性动画(Property Animation)

下面我们着重介绍下属性动画,干货来了

1、属性动画的特性:

  • a.支持对所有View能更新的属性的动画(需要属性的setXxx()和getXxx())。
  • b. 更改的是View实际的属性,所以不会影响其在动画执行后所在位置的正常使用。
  • c. Android3.0(API11)及以后出现的功能,3.0之前的版本可使用github第三方开源库nineoldandroids.jar进行支持。

2、属性动画的优缺点:

  • 缺点:(3.0+API出现)向下兼容问题
  • 优点:易定制,效果强

3、属性动画的实现:

相比帧动画和补间动画的不同之处属性动画可以不用在资源文件中定义动画也能达到动画效果,而且它可以任意组合动画,组合动画可以一次进行,也可以同时进行,达到了更加炫酷的效果,下面就来看看在代码中如何让使用:


/**
 * 属性动画
 *
 * @author wangyangke
 * @date:2016.9.2 @time 01:12
 */
public class PropertyActivity extends AppCompatActivity {
    private ImageView iv;
    Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_property);
        iv = (ImageView) findViewById(R.id.iv);
        btn = (Button) findViewById(R.id.btn);
    }

    public void mToast(View iv) {
        Toast.makeText(this, "图片被点击了!", Toast.LENGTH_SHORT).show();
    }

    public void play1(View view) {
        //btn.setTranslationX(100);
        //100 当前View X坐标的差值
        TranslateAnimation animation = new TranslateAnimation(0, 100, 0, 0);
        animation.setDuration(1000);
        animation.setFillAfter(true);
        iv.startAnimation(animation);
    }

    public void play2(View view) {
        //1.属性动画ObjectAnimator
        //btn.setTranslationX(translationX)
        //translationX 属性 float类型
        //这个属性动画,改变的是translationX的属性值,0,100
        //translationX 调用这个属性的setter和getter方法
        ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
        oa.setDuration(1000);
        oa.start();
        //c.getMethod("setTranslationX", int.class);
    }

    public void play3(View view) {
        //3.属性存储器
        PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 0, 100);
        //缩放动画,X Y轴缩放比例从原始比例,缩小到最小,再放大到原始比例1f
        PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
        PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
        //同时执行三个动画
        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(iv, pvh1, pvh2, pvh3);
        oa.setDuration(1000);
        oa.start();
    }

    public void play4(View view) {
        //4.执行集合类
        //一组动画的执行集合类:设置执行的先后顺序,时间等
        AnimatorSet set = new AnimatorSet();
        //透明度
        ObjectAnimator anim1 = ObjectAnimator.ofFloat(iv, "alpha", 0f, 1f);
        anim1.setDuration(4000);
        //横向平移
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(iv, "translationX", 0f, 100f);
        anim2.setDuration(3000);
        //纵向平移
        ObjectAnimator anim3 = ObjectAnimator.ofFloat(iv, "translationY", 0f, 100f);
        anim3.setDuration(3000);
        //旋转
        ObjectAnimator anim4 = ObjectAnimator.ofFloat(iv, "rotation", 0f, 360f);
        anim4.setDuration(500);

        //制定动画执行的顺序
        //anim1 在 anim2 之前执行
        set.play(anim1).before(anim2);
        //anim2 anim3 同时执行
        set.play(anim2).with(anim3);
        //anim4 在 anim3之后执行
        set.play(anim4).after(anim3);

        set.start();
    }

    public void play5(View view) {
        //5.关键帧
        //Keyframe 定义动画在特定的时间点上特定的状态
        //第一个0,动画的执行进度,第二个0,初始的状态(0度)
        Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
        //动画执行到30%时,应该旋转了360度
        Keyframe kf1 = Keyframe.ofFloat(0.2f, 360f);
        //动画执行到100%,重新旋转到0度
        Keyframe kf2 = Keyframe.ofFloat(1f, 0f);


        //区别:ObjectAnimator.ofFloat(iv, "rotation", 0f,360f,0f);
        //将关键帧打包
        PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
        //创建属性动画对象
        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(iv, holder);
        oa.setDuration(2000);
        oa.start();
    }

    public void play6(View view) {
        //6. 动画执行监听
        //AnimatorListener
        ObjectAnimator oa = ObjectAnimator.ofFloat(btn, "alpha", 1f, 0f);
        oa.setDuration(1000);
        oa.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
                //动画开始时调用
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                //动画重复时调用
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                ////动画结束时调用
                //移除按钮
                ViewGroup parent = (ViewGroup) btn.getParent();
                if (parent != null) {
                    parent.removeView(btn);
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                //动画取消时调用
            }
        });
        oa.start();
    }

    public void play7(View view) {
        //7.TimeInterpolator :时间插值,用于控制动画执行过程

        ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationY", 0, 300);
        oa.setDuration(1500);
        oa.setInterpolator(new BounceInterpolator());
        oa.start();

    }

    public void play8(View view) {
        //8.ValueAnimator值动画执行类,常配合AnimatorUpdateListener使用
        //区别:不需要在“构造方法”中指定需要更新的属性

        final View btn8 = findViewById(R.id.btn8);
        ValueAnimator va = ValueAnimator.ofFloat(0f, 200f);
        //ObjectAnimator.ofFloat(iv, "translationX", 0f,200f);
        //va.setTarget(iv);
        va.setDuration(2000);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = Float.parseFloat(animation.getAnimatedValue().toString());
                ViewHelper.setTranslationX(iv, v);
                //优点:可以同时在回掉方法中,更新多个控件的属性
                //使用ObjectAnimator还是ValueAnimator取决于是否在一个动画中更新多个控件的属性
                ViewHelper.setTranslationY(btn8, v);
            }
        });
        va.start();

    }

    public void play9(View view) {
        //9.TypeEvaluator类型估值,用于设置复杂的动画操作属性的值
        //(0,100)->(100,200)
        //现有的int、float类型的值,已经无法满足我们的需求了,我们需要自己的值类型
        //抛物线效果

        final PointF point = new PointF();
        TypeEvaluator typeEvaluator = new TypeEvaluator() {
            //
            @Override
            public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
                //fraction 就相当于进度0->1
                //动画执行的当前时间
                float time = fraction * 3;//3秒
                //x方向速度:200px/s
                //y方向速度:
                point.x = 200 * time;
                point.y = 0.5f * 200 * time * time;

                return point;
            }
        };

        ValueAnimator valueAnimator = ValueAnimator.ofObject(typeEvaluator, new PointF(0, 0));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //getAnimatedValue方法返回的值,由evaluate计算得到的
                PointF point = (PointF) animation.getAnimatedValue();
                ViewHelper.setX(iv, point.x);
                ViewHelper.setY(iv, point.y);
            }
        });
        valueAnimator.setDuration(3000);
        valueAnimator.start();

    }

}

三者最大的区别

属性动画,顾名思义直接是改变的控件的属性。仔细的同学可能会发现:在补间动画中即使他的位置发生了变化,但是他的诸如 点击事件,监听 ,都还停留在原地,不会跟着控件位置的变化去跟着改变。属性动画最大的特点就是 保留了这些监听之类的属性,即使位置发生变化也不会影响它的使用。

列表内容

Android内置动画

androidSDK内置动画也很丰富,一些简单的动画,google工程师已经为我们写好了,只需要调用即可

总结

动画的效果取决与程序员,你能想到的效果几乎都能实现,只不过是难易程度,时间花费,以及程序员的空间想象能力,思考能力有关,以上实现的只是很简单的属性动画,一部分人还是比较喜欢直接在网上搜索想要的效果直接用,可能连原理都不知道,这是作为一个程序员不应该的。希望大家可以自己去试着做一些自己觉的炫酷的动画效果,而不仅仅是依赖网络,这样做出效果后相信自己的成就感也不言而谕。

尾声

自己对属性动画还没有研究的很深,希望大家提出宝贵的意见或者建议,共同进步。

源码地址:http://download.csdn.net/detail/nanxuan521/9636672

你可能感兴趣的:(android)