Android屬性動畫欣賞——ObjectAnimator與動畫監聽事件
阿新 • • 發佈:2019-01-26
傳統動畫的侷限
傳統動畫(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();
}
}
}
}