android開發中用到的動畫實現方式有三種,即View動畫、Drawable動畫以及屬性動畫三種動畫的實現方式,關於這些動畫的實現方式網上很多文章都總結的很詳細了,寫這篇文章完全是爲了自己總結記錄,而且本文不會去追究代碼細節的問題,就單單總結下怎麼用的問題,具體代碼細節的話,請參考本文的參考文獻。
1、View動畫
View動畫的實現是通過View控件的setAnimation來設置動畫,可以設置的動畫有限,只有以下四種
- AlphaAnimation: 透明度動畫
- RotateAnimation: 旋轉動畫
- ScaleAnimation: 縮放動畫
- TranslateAnimation: 平移動畫
四種動畫的作用看名字應該就清楚了,這裏以RotateAnimation爲例來說說使用View動畫的兩種方式
第一種是通過xml的方式來實現(三種動畫實現方式都可以通過xml配置的方式來實現),在res/anim目錄下創建一個view_animation_rotate.xml 內容如下
<!--
* android:fromDegrees="-50":動畫開始執行時的控件起始狀態的角度;
* android:toDegrees="360":動畫結束執行時的控件結束狀態的角度;
* android:pivotX="50%":旋轉動畫的中心點的X軸方向的橫座標,Value正值(例如50%)時,意思是相對於控件的原始位置往右方向的50%控件寬度的位置爲橫座標,
* 若Value爲負值(例如-50%),則表示往左方向;當Value爲數值時,則代表相對於屏幕的(px)像素值;
* android:pivotY="50%":旋轉動畫的中心店的Y軸方向的縱座標,原理同上;
* android:startOffset="1000":動畫執行前的延遲時間;
* android:fillAfter="true":當Value爲true,表示動畫執行結束後停留在結束後的狀態;
* android:duration="2500":設置每一次動畫持續的時間值,單位爲毫秒(ms);
* android:repeatCount="5":設置動畫重複的次數;
* android:repeatMode="reverse":設置動畫重複的模式:
* reverse爲0.0 -> 1.0 -> 0.0,動畫反覆執行;
* restart爲0.0 -> 1.0, 0.0 -> 1.0,動畫每次都重新開始執行
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="520"
android:toDegrees="3600"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="1000"
android:fillAfter="true"
android:duration="2500"
android:repeatCount="4"
android:repeatMode="reverse"
/>
定義好xml後,便可通過AnimationUtils類來加載xml生成一個動畫對象,注意這個AnimationUtils類不是我們自己定義的類,而是Android Sdk提供的android.view.animation包中的類。
/**
* xml文件加載圖片旋轉(Rotate)動畫
*/
RotateAnimation mAnimation = AnimationUtils.loadAnimation(this, R.anim.view_animation_rotate);
這裏生成了一個RotateAnimation的對象,調用view.setAnimation(mAnimation)便設置好了view控件的動畫。
當然另外一種實現ViewAnimation的方法就是直接通過new RotateAnimation的方式實現,並且在新建的時候傳入基本動畫參數。
/**
* 代碼創建圖片旋轉(Rotate)動畫
* mAnimation = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
* fromDegrees:動畫開始執行時的控件起始狀態的角度;
* toDegrees:動畫結束執行時的控件結束狀態的角度;
* pivotXType:動畫在X軸相對於物件位置類型 ,分爲RELATIVE_TO_SELF、RELATIVE_TO_PARENT和ABSOLUTE三種類型:
* 1、RELATIVE_TO_SELF:相對於控件自身;
* 2、RELATIVE_TO_PARENT:相對於父控件;
* 3、ABSOLUTE:絕對座標;
* pivotXValue:動畫開始執行時X軸方向的的起始位置,當位置類型爲RELATIVE_TO_SELF時,Value取0.0f~1.0f之間,當位置類型爲RELATIVE_TO_PARENT或ABSOLUTE時,Value使用(px)像素值;
* pivotYType:動畫在Y軸相對於物件位置類型 ,分爲RELATIVE_TO_SELF、RELATIVE_TO_PARENT和ABSOLUTE三種類型;
* pivotYValue:旋轉動畫的中心點的Y軸方向的縱座標,原理同上;
*/
//mAnimation = new RotateAnimation(fromDegrees, toDegrees)
//mAnimation = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY)
RotateAnimation mAnimation = new RotateAnimation(-50f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mAnimation.setDuration(2000);
到這類兩種實現View動畫的方式就說清楚了,當然我們可能有將四種View動畫方式結合起來使用,這個需求也好辦,可通過AnimationSet這個動畫集合類來實現,也可以在通過在res/anim目錄下的xml文件中配置多個動畫的方式來實現,這裏就不展開說明了。
2、Drawable動畫
Drawable動畫名稱來自於實現Drawable動畫的xml文件時放在res/drawable目錄中的,比如我們要實現一個機器人走動的動畫,那麼便可在drawable中放置機器人走動的圖片
然後在res/drawable下創建drawable_animation_robot.xml文件,內容如下
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/drawable_animation01" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation02" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation03" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation04" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation05" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation06" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation07" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation08" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation09" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation10" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation11" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation12" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation13" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation14" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation15" android:duration="80"/>
<item android:drawable="@drawable/drawable_animation16" android:duration="80"/>
</animation-list>
設置好xml後,便可通過下面代碼去獲得Drawable動畫
//設置背景
view.setBackgroundResource(R.drawable.drawable_animation_robot);
//獲取當前的背景
mAnimationDrawable = (AnimationDrawable) view.getBackground();
通過以下代碼便可以開啓動畫或者關閉動畫
//開啓動畫
mAnimationDrawable.start();
//關閉動畫
mAnmationDrawable.stop();
到這類Drawable動畫就算是說清楚了。
3、屬性動畫
屬性動畫是三種動畫實現裏最複雜的也是最靈活的,它通過去設置控件的屬性從而實現動畫效果,與屬性動畫相關且的有以下一些類
- ObjectAnimator: 動畫執行類
- ValueAnimator: 動畫執行類
- AnimatorSet: 用於控制一組動畫的執行
- AnimatorInflater : 用戶加載屬性動畫xml文件
- TypeEvaluator: 類型估值器
- TimeInteplotor:時間插值器
上面的這些類在實現屬性動畫時會被經常用到,下面來進行分別講解。
3.1 ObjectAnimator 、 ValueAnimator 、 AnimatorSet這幾個類的使用
從以上類中可以看出動畫執行類主要有兩個,分別是ObjectAnimator和ValueAnimator,其主要區別在於ObjectAnimator在實現動畫的時候需要首先指定動畫屬性,而ValueAnimator則不需要,ValueAnimator是在addUpdateListener中通過set方法去指定屬性。
ObjectAnimator實現動畫
ObjectAnimator
.ofFloat(view, "rotationY", 0.0F, 360.0F)//指定了屬性rotationY
.setDuration(500)
.start();
ValueAnimator實現動畫
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - mBlueBall.getHeight());
animator.setTarget(mBlueBall);
animator.setDuration(1000).start();
animator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//在addUpdateListener中通過set方法指定屬性
mBlueBall.setTranslationY((Float) animation.getAnimatedValue());
}
});
這裏我們看到無論是使用ObjectAnimator還是ValueAnimator這裏都是對一個屬性進行的動畫操作,那麼如果要同時操作幾個屬性動畫呢?當然我們可以使用AnimatorSet類去實現,但是如果我們不使用AnimatorSet類呢?
針對ObjectAnimator可以使用addUpdateListener的方式實現
ObjectAnimator anim = ObjectAnimator
.ofFloat(view, "zhy", 1.0F, 0.0F)
.setDuration(500);
anim.start();
anim.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float cVal = (Float) animation.getAnimatedValue();
view.setAlpha(cVal);
view.setScaleX(cVal);
view.setScaleY(cVal);
}
});
這裏的缺點很明顯,就是三個屬性,我們設置的變化參數卻只有一個,於是針對ObjectAnimator我們可以使用PropertyValuesHolder類來完成多屬性動畫操作,來解決這個問題
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
這裏針對多屬性,便可以有有多個變化參數去設置動畫效果。
ValueAnimator實現多屬性動畫操作同樣的可以使用addUpdateListener以及PropertyValuesHolder兩種方法。
當然實現多屬性動畫操作,還可以使用AniamtorSet這個類來實現
AnimatorSet實現動畫集合
使用AnimatorSet這個類可以規定動畫的執行先後順序,各自的執行時間等,使用起來特別靈活
float cx = mBlueBall.getX();
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX", 1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY", 1.0f, 2f);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall, "x", cx , 0f);
ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall, "x", cx);
/**
* anim1,anim2,anim3同時執行
* anim4接着執行
*/
AnimatorSet animSet = new AnimatorSet();
animSet.play(anim1).with(anim2);
animSet.play(anim2).with(anim3);
animSet.play(anim4).after(anim3);
animSet.setDuration(1000);
animSet.start();
3.2 AnimatorInflater類的使用
前面講View動畫和Drawable動畫的時候都提到了xml來實現動畫的方式,而屬性動畫也可以通過xml的方式下來實現動畫效果,其就是藉助了AnimatorInflater這個類來實現。
AnimatorInflater類加載額xml文件放在res/animator/目錄下,這裏創建一個rotation.xml文件,內容爲
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="rotationX"
android:duration="1000"
android:valueType="floatType"
android:valueFrom="0.0"
android:valueTo="360.0">
</objectAnimator>
然後藉助AnimatorInflater類來加載xml動畫
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.rotation);
animator.setTarget(view);
animator.setDuration(2000);
animator.setInterpolator(new LinearInterpolator());
animator.start();
這樣便通過使用AnimatorInflater加載xml完成了一個屬性動畫的操作。
3.3 TypeEvaluator 、 TimeInterpolator這兩個類的使用
前面提到TypeEvaluator叫做類型估值器,TimeInterpolator叫做時間插值器,類型估值器用來動態的設置屬性變化,而時間插值器用來設置時間相對動畫的變化效果。簡單的說,TimeInterpolator控制動畫的速度,而TypeEvaluator控制動畫的值。這兩個類的使用比較靈活,可以去參考模擬自然動畫的精髓——TimeInterpolator與TypeEvaluator這篇文章,這裏舉一個模擬拋物線的動畫來進行說明。
如果我希望小球拋物線運動【實現拋物線的效果,水平方向100px/s,垂直方向加速度200px/s*s 】,分析一下,貌似只和時間有關係,但是根據時間的變化,橫向和縱向的移動速率是不同的,我們該咋實現呢?此時就要重寫TypeEvaluator了,因爲我們在時間變化的同時,需要返回給對象兩個值,x當前位置,y當前位置。
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<PointF>()
{
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue)
{
Log.e(TAG, fraction * 3 + "");
// x值爲200 * t ,而y值爲0.5 * 10 * t * t
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 10 * (fraction * 3) * (fraction * 3);
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
PointF point = (PointF) animation.getAnimatedValue();
mBlueBall.setX(point.x);
mBlueBall.setY(point.y);
}
});
從代碼可以看出重新定義了類型估值器,設置了x y值得變化,同時將時間插值器設置爲默認的線性變化,那麼最終小球將以拋物線的動畫運動。
4、參考文獻
本文基本代碼都是從其它參考文獻拷貝過來,略加修改的,感謝這些作者的辛勤奉獻。
1、 Android 屬性動畫(Property Animation) 完全解析 (上)
3、Android動畫之一:Drawable Animation
4、Android 動畫學習(一)之View Animation