初识android动画(4)之属性动画

来源:互联网 发布:windows 10桌面美化 编辑:程序博客网 时间:2024/06/12 22:32

     属性动画算是Android动画里面比较麻烦的一种动画了。不过就是因为它麻烦所以也能更好地满足我们的需求。属性动画是在3.0以后添加的。功能十分强大。接下来我们将重点的讲讲。如果对其他几种动画不了解的话可以先看看我的前几篇博客初识android动画。下面的内容均在前几篇的基础上讲的。我们看一下官方提供的使用属性动画制作的酷炫的例子吧!!!

     先给出官方的API       点击打开链接

 

     属性动画与传统动画的区别

  

         当我们点击按钮的时候,一个圆由位置一转到位置二。我们也为这个圆设置一个点击事件,当点击圆的时候弹出一个Toast。我们传统的做法是什么呢?肯定是设置一个传统的TranslateAnimation属性,为其设置位置就可以了。现在我们在位置一点击圆肯定能弹出一个Toast。但是我们的位置发生变化之后,我们再去点击圆发现没有Toast了。但是我们在原来的位置一上点击发现能够Toast,怎么回事呢?这就是传统动画的弊端了。 传统动画考虑的是一个View的重新绘制。当我们执行动画的时候其实就是一个个View不断地去重新绘制。而我们的属性动画就可以很好的解决这一问题。

        属性动画一:ObjectAnimator

  ObjectAnimator是属性动画里面比较简单但是也是会经常用到的一个对象。他其实执行的是一个异步任务。我们再给出官方的API  点击打开链接

 那么我们如何去使用呢?接着前面提到的一个例子       

    我们定义了一个按钮,一张图片。点击按钮启动动画;

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }        //图片的点击事件    public void click(View view){    Toast.makeText(MainActivity.this, "点击了图片", Toast.LENGTH_SHORT).show();    }        //按钮的监听事件    public void move(View view){    ImageView imageView=(ImageView) findViewById(R.id.imageView1);        ObjectAnimator animator=new ObjectAnimator();    animator.ofFloat(imageView, "translationX", 0f,200f).start();    } }

 我们看到,我们用属性动画特别的简单,就是一句话,而且用属性动画,我们也很好的解决了上面的问题。当我们使用其他属性的时候,直接调用其他的就好。在这里我们使用了TranslationX.当然我们还有其他的一些属性。
       

如果我们使用ObjiecAnimation为ImageView同时定义多个动画会怎么样呢?答案就是同时会播放这几个动画。下面看一下还有没有其他的几种方法

           (1)同时使用ObjiecAnimator
   我们将上面MainActivity中的代码修改一下
ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000).start();    ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000).start();    ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000).start();
            (2)同时使用PropertyVlaueHolder:
使用这种属性的好处就是他的性能好, 节省系统资源
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationX",0f,200f);    PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationY", 0f,200f);    PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("rotation", 0f,360f);    ObjectAnimator.ofPropertyValuesHolder(imageView, p1,p2,p3).setDuration(3000).start();
            (3)使用AnimatorSet
    ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);    ObjectAnimator animator2=ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000);    ObjectAnimator animator3=ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000);    AnimatorSet set=new AnimatorSet();    set.playTogether(animator1,animator2,animator3);    set.start();
 我们使用以上的三种方法都可以实现同时播放我们的好几种动画。其中AnimatorSet功能最为强大。不仅仅可以同时播放好几种动画,还可以控制动画的播放顺序
          //按照顺序依次播放      set.playSequentially(animator1,animator2,animator3);     //动画2和动画3同时播放,动画一在他们之后播放      set.play(animator2).with(animator3);      set.play(animator1).after(animator2);

    属性动画二:监听事件

     有时候我们在动画播放的过程中,或者前后会引发一系列事件,这时候我们就可以添加
ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);    //添加监听事件    animator1.addListener(new AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationRepeat(Animator animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationEnd(Animator animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationCancel(Animator animation) {// TODO Auto-generated method stub}});            //有选择的添加监听事件    animator1.addListener(new AnimatorListenerAdapter() {    @Override    public void onAnimationEnd(Animator animation) {    // TODO Auto-generated method stub    super.onAnimationEnd(animation);    }});
代码很简单一眼就能明白。

       属性动画三:  ValueAnimator数值发生器

  什么是ValueAnimator呢?
       前面我们提到ObjectAnimator可以定义一个动画到View的某一个属性。其实ObjectAnimator就是继承了ValueAnimator。 而ValueAnimator则不会产生这样一种效果。它的本质就是一个数值发生器。他可以产生你想要的各种数值。他可以计算属性动画中每一步的具体动画效果。ValueAnimator会根据动画已进行的时间与其持续的总时间的比值产生一个0~1的时间因子,有了这样一个时间因子,经过相应的变换,就可以根据startValue()和endValue()来生产中间的相应值。同时,通过插值器的使用,可以进一步地控制每一个时间因子产生值的变化速率。下面看一看该如何用?这里使用一个数值计算器。
        我们要实现的效果是什么呢,就是在点击一个按钮之后,按钮的显示内容会从0-10不断地递增。如果按照以前的做法,我们肯定是在线程中定义一个for循环,每一段时间更新一个数值。其实呀,这种方法是非常的耗费系统资源的。ValueAnimator也可以实现这样的一种效果。
      
  下面是实现的代码
  
public class MyActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {setContentView(R.layout.my_activity);super.onCreate(savedInstanceState);}public void click(View view){//获得Button对象final Button button=(Button)findViewById(R.id.my_button);//新建一个ValueAnimator,让其中的数值从0-10ValueAnimator animator=ValueAnimator.ofInt(0,10);//从0-10在10秒内变化animator.setDuration(10000);//为其添加事件animator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {//获得ValueAnimator的植Integer value=(Integer) animation.getAnimatedValue();button.setText(""+value);}});animator.start();//启动动画}}
         我们看到没有使用线程。也可以实现。现在大家应该能够自然而言的想到一些其他的一些应用场景了吧。例如在0-3之间我们产生一个时间,3-7之间做另外一件事等等。上面我们直接使用的ofInt。这是谷歌给我定义好的一种模式。那我们能不能自己定义一些数值计算器呢?答案是肯定的。
//自定义数值计算器ValueAnimator animator=ValueAnimator.ofObject(new TypeEvaluator<PointF>() {//通过evaluate返回各种各样的植,我们拿到这些值之后就可以为所欲为了。@Overridepublic PointF evaluate(float arg0, PointF arg1, PointF arg2) {// TODO Auto-generated method stubreturn null;}});
 fraction:   :时间因子,从0-1之间变化              arg1   :开始值            arg2  :结束值
我们自定义这些值可以应用到插值器中:定义自己的插值器。如果对插值其不了解的话。看我的另外一篇博客
初始android动画
   下面给一张插值器的数值变化表,
    

    总结:

            下面总结了一下属性动画中常用的一些方法类和接口。
                 
    接下来根据前面学的知识,做一个小的案例。先看一下效果:
      
先在我们res/drawable/文件中添加一些列图片。然后在布局文件中声明:
<FrameLayout 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">    <ImageView        android:id="@+id/imageView_h"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/h" />       <ImageView        android:id="@+id/imageView_g"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/g" />      <ImageView        android:id="@+id/imageView_f"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/f" />       <ImageView        android:id="@+id/imageView_e"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/e" />        <ImageView        android:id="@+id/imageView_d"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/d" />         <ImageView        android:id="@+id/imageView_c"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/c" />         <ImageView        android:id="@+id/imageView_b"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/b" />         <ImageView        android:id="@+id/imageView_a"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/a" />  </FrameLayout>
然后在我们activity中运用就可以了。
public class MainActivity1 extends Activity implements OnClickListener {//定义一些图片资源private int[] res = { R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,R.id.imageView_d, R.id.imageView_e, R.id.imageView_f, R.id.imageView_g, R.id.imageView_h };//保存图片private List<ImageView> imageViewList = new ArrayList<ImageView>();//用于控制图片伸缩开关private boolean flag=true;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//将图片添加进来for (int i = 0; i < res.length; i++) {ImageView imageView = (ImageView) findViewById(res[i]);imageView.setOnClickListener(this);imageViewList.add(imageView);}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.imageView_a:if(flag){startAnim();}else{stopAnim();}break;}}//停止播放动画@SuppressLint("NewApi")private void stopAnim() {for (int i = 0; i < res.length; i++) {ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i), "translationY", i * 100, 0f);animator.setInterpolator(new BounceInterpolator());//插值器animator.setDuration(1000);animator.setStartDelay(i * 500);animator.start();flag=true;}}//开始播放动画@SuppressLint("NewApi")private void startAnim() {for (int i = 1; i < res.length; i++) {ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i), "translationY", 0f, i * 100);AnimatorSet mset=new AnimatorSet();mset.playTogether(animator);mset.setDuration(1000);mset.setStartDelay(i*500);mset.setInterpolator(new BounceInterpolator());//插值器mset.start();flag=false;}}}
    如果看懂了源码之后你也可以自己修改制作各种不同的效果。
点击下载源码:点击下载


1 0