1. 程式人生 > >Android屬性動畫欣賞——ObjectAnimator與動畫監聽事件

Android屬性動畫欣賞——ObjectAnimator與動畫監聽事件

傳統動畫的侷限
傳統動畫(Animation)只是重繪動畫(就是不斷的呼叫相應的方法重繪,會耗費CPU資源),改變其顯示位置,但是真正能響應事件的位置還在原處。因此不適宜做具有互動的動畫效果,僅僅用來做一些顯示性的效果。(包括位移、旋轉、縮放、透明度四種動畫)

比如將一個ImageView平移一段距離,且在ImageView上加上點選事件,顯示的時候圖片是平移了的,但是在點選平移後的圖片不能響應點選事件,而點選原來的位置卻能響應點選事件。

程式碼演示:
1.佈局檔案,包括一個按鈕觸發動畫,一個ImageView用來顯示動畫,且ImageView自帶有點選事件,點選之後能彈出一個Toast

<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" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="110dp" android:onClick="move" android:text="Move" />
<ImageView android:id="@+id/imageView"
android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:background="@drawable/ic_launcher" />
</RelativeLayout>

2.程式碼實現

public class MainActivity extends Activity {
    ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv=(ImageView) findViewById(R.id.imageView);
        iv.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void move(View view) {
        //傳統動畫
        TranslateAnimation animation=new TranslateAnimation(0,200,0,0);
        animation.setDuration(1000);
        animation.setFillAfter(true);//使ImageView停在動畫停止的位置
        iv.startAnimation(animation);

        //三種實現屬性動畫的途徑

        //第一種
//      ObjectAnimator.ofFloat(iv, "translationX", 100F,150F).setDuration(1000).start();//平移
//      ObjectAnimator.ofFloat(iv, "rotation", 0F,180F).setDuration(2000).start();//旋轉

        //第二種
//      //谷歌在PropertyValuesHolder類中對動畫進行了優化,在使用多個屬性動畫時,能更加有效率,更加節省系統資源
//      PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationX", 100F,200F,150F);
//      PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("rotation", 0F,360F,180F);
//      ObjectAnimator.ofPropertyValuesHolder(iv, p1,p2).setDuration(1000).start();

        //第三種
        //提供了更加豐富的動畫控制效果,可以一起顯示,也可以按順序顯示,達到更加精細的操作效果
//      ObjectAnimator animator1=ObjectAnimator.ofFloat(iv, "translationX", 0F,200F);
//      ObjectAnimator animator2=ObjectAnimator.ofFloat(iv, "rotation", 0F,180F);
//      ObjectAnimator animator3=ObjectAnimator.ofFloat(iv, "translationY", 0F,200F);
//      AnimatorSet set = new AnimatorSet();
//      set.play(animator1).with(animator3);//animator1與animator3一起顯示
//      set.play(animator2).after(animator1);//animator2在顯示完animator1之後再顯示
//      set.playTogether(animator1,animator2);//一起顯示
//      set.playSequentially(animator1,animator2);//按照順序顯示
//      set.setDuration(5000);//記住setDuration要在play以及playXXX方法之後,否則,設定的時間是不起作用的
//      set.setInterpolator(new BounceInterpolator());//設定插值器,BounceInterpolator使得動畫具有像小球落在地上回彈一樣的效果,也要在play以及playXXX方法之後
//      set.start();


        ObjectAnimator animator=ObjectAnimator.ofFloat((Button)findViewById(R.id.button1), "alpha", 0F,1F); 
        //實現動畫的監聽
//      animator.addListener(new AnimatorListener() {//監聽動畫在不同的時間段所需要完成的操作
//          
//          @Override
//          public void onAnimationStart(Animator animation) {
//          }
//          
//          @Override
//          public void onAnimationRepeat(Animator animation) {
//          }
//          
//          @Override
//          public void onAnimationEnd(Animator animation) {
//              Toast.makeText(MainActivity.this, "The End", Toast.LENGTH_LONG).show();
//          }
//          
//          @Override
//          public void onAnimationCancel(Animator animation) {
//          }
//      }); 
        animator.addListener(new AnimatorListenerAdapter() {//便利類,只要實現需要的方法
            @Override
            public void onAnimationEnd(Animator animation) {
                Toast.makeText(MainActivity.this, "The End", Toast.LENGTH_LONG).show();//在動畫結束後顯示一個Toast
            }
        });
        animator.setDuration(1000);
        animator.start();
    }
}

在使用傳統動畫的時候,因為在程式碼中實現了將ImageView停在動畫停止的位置,所以在第二次點選按鈕的時候,會出現重影(並且點選停止後的機器人圖片根本不會有Toast彈出)如下圖:
這裡寫圖片描述
原始碼:http://download.csdn.net/download/qq_22804827/9413534
而屬性動畫顯示的時候,就算在顯示的過程中點選機器人圖片也會響應點選事件,彈出Toast。

在簡單的瞭解了屬性動畫之後,實踐一下,做一個比較流行的“衛星選單”,演示效果如下:
這裡寫圖片描述

1.佈局檔案

<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/iv_e"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingTop="5dp"
        android:src="@drawable/e"/>

    <ImageView 
        android:id="@+id/iv_d"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingTop="5dp"
        android:src="@drawable/d"/>

    <ImageView 
        android:id="@+id/iv_c"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingTop="5dp"
        android:src="@drawable/c"/>

    <ImageView 
        android:id="@+id/iv_b"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingTop="5dp"
        android:src="@drawable/b"/>

    <ImageView 
        android:id="@+id/iv_a"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="2dp"
        android:paddingTop="2dp"
        android:src="@drawable/a"/>

</FrameLayout>

2.程式碼實現

public class MainActivity extends Activity implements OnClickListener {
    private int[] ivIds = { R.id.iv_a, R.id.iv_b, R.id.iv_c, R.id.iv_d, R.id.iv_e};
    private ImageView[] imageViews = new ImageView[ivIds.length];
    private boolean isOpen;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for (int i = 0; i < ivIds.length; i++) {
            imageViews[i] = (ImageView) findViewById(ivIds[i]);
            imageViews[i].setOnClickListener(this);
        }
        isOpen=true;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.iv_a: 
            executeAnim(isOpen);
            isOpen=!isOpen;
            break;
        default:
            Toast.makeText(MainActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
            break;
        }
    }

    private void executeAnim(boolean isOpen) {
        if (isOpen) {
            float defRadius = TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP, 100, this.getResources()
                            .getDisplayMetrics());
            double angle = 30f;
            for (int i = 1; i < 5; i++) {
                double sin = Math.sin(Math.toRadians(angle * (i - 1)));
                double cos = Math.cos(Math.toRadians(angle * (i - 1)));
                int x = (int) (defRadius * sin);
                int y = (int) (defRadius * cos);
                Log.d("座標", angle + " " + x + " " + y);

                ObjectAnimator animator1=ObjectAnimator.ofFloat(imageViews[i],"X", 0F,x);
                ObjectAnimator animator2=ObjectAnimator.ofFloat(imageViews[i],"Y", 0F,y);
                AnimatorSet set=new AnimatorSet();                              
                set.playTogether(animator1,animator2);
                set.setInterpolator(new BounceInterpolator());//設定插值器,BounceInterpolator使得動畫具有像小球落在地上回彈一樣的效果
                set.setDuration(5000);
                set.start();
            }
        }
        else {
            for(int i=1;i<5;i++) {
                PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("X", imageViews[i].getX(),
                        0F);
                PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("Y", imageViews[i].getY(),
                        0F);
                ObjectAnimator.ofPropertyValuesHolder(imageViews[i], p1, p2)
                        .setDuration(500*i).start();
            }
        }
    }
}