您好,登錄后才能下訂單哦!
簡介
Android 開發中,總是需要一些動畫來優化用戶的交互體驗,提高用戶滿意度。因此,Google 為我們提供了一些用于處理動畫效果的動畫框架。Android 的動畫框架分為兩類:
傳統動畫框架的局限性
既然有了傳統動畫框架,Google 為什么還要創造一個屬性動畫框架呢?
我們下面舉個例子來說明一下傳統動畫的局限性。
在布局中加入一個 ImageView 和一個 Button,點擊 ImageView 后彈出一個 Toast,點擊 Button 后使 ImageView 展現一個向右平移的動畫效果。
下面是使用傳統動畫實現的代碼:
TranslateAnimation animation = new TranslateAnimation(0,200,0,0); // 平移動畫x軸移動200,y軸不動 animation.setDuration(1000); // 動畫時長 animation.setFillAfter(true); // 使動畫結束后停留在結束的位置 mIvPicture.startAnimation(animation);
運行后,ImageView 確實進行了我們預期的平移的效果。可是當我們嘗試點擊 ImageView 當前的位置時,卻沒有 Toast 彈出。我們再嘗試去點擊 ImageView 開始動畫前的位置,卻成功彈出了 Toast。
這就是傳統動畫很大的局限性:
因此,Google 為我們提供了一套全新的屬性動畫框架,來讓我們實現更豐富的動畫效果。
ObjectAnimator
ObjectAnimator 是屬性動畫中,最簡單也最常用的一個對象。
實現 Animation 框架的功能
平移
前文提到的使 ImageVIew 向右平移 200 像素的動畫效果,使用屬性動畫只需要很簡單的幾句代碼即可實現:
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F) .setDuration(1000) .start();
我們來分析一下這一句代碼。我們調用了ofFloat代碼,并傳入三個參數。
第一個參數是動畫需要操縱的目標,在這里是我們的 ImageView。
第二個參數是所需要操縱的目標所具備的屬性名稱。
第三個參數是這個動畫變化的取值范圍。
最后設置一下它的動畫的屬性,便可以 start 了。
這次我們再次點擊 ImageView 目前的位置,成功地彈出了 Toast。這證實了屬性動畫是通過改變物體的屬性來達到動畫效果的理論。
當我們需要改變 y 坐標時,只需要把 "translationX" 變為 "translationY" 即可。
其實 ,只要Google對一個對象的某個屬性提供了get和set方法,我們就可以使用這個屬性來實現動畫效果。
其實我們還能用 X Y 兩個屬性實現之前的動畫效果,那么對象屬性中 X 的 Y 與 translationX translationY 有什么區別呢?
translationX translationY指的是物體的偏移量,而X Y則表示它最終到達的絕對位置。
旋轉
旋轉屬性使用的是 "rotation" 屬性,后面的變換范圍的單位是角度。
比如想讓 ImageView 旋轉90度,只需要
ObjectAnimator.ofFloat(mIvPicture,"rotation",0F,90F) .setDuration(1000) .start();
其他
其實屬性動畫能操縱的屬性,只要具有 set、get 方法,都可以進行操縱。如 scaleX、scaleY 等等...
插值器
Android 為我們內置了插值器,使我們的動畫更為自然。比如可以讓我們的平移動畫像物體的重力加速度由快到慢的 Accelerate 等等
Android中內置了七種插值器,分別是
要應用插值器,可以調用 ObjectAnimator 的 setInterpolator 方法, new 出對應的插值器作為參數(xxxInterpolator)。比如下面這段代碼:
animator.setInterpolator(new AccelerateInterpolator());
通過插值器,我們可以讓動畫的效果更佳自然。
多種屬性動畫同時作用
當我們把幾種動畫按順序寫下時,運行程序,會發現效果是三種屬性動畫的疊加。由此可以發現,屬性動畫在調用 start 方法后,實際上是一個異步的過程。因此我們就可以看到三個屬性動畫同時作用的效果。通過這樣的方法,其實就可以實現多種屬性動畫同時作用的效果:
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"rotationX",0F,360F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"translationY",0F,200F).setDuration(1000).start();
其實 Google 為我們提供了更好的方法,來實現這樣的效果。
我們可以使用 PropertyValuesHolder 來實現。其構造函數僅僅比 ObjectAnimator 少了一個作用對象參數。之后通過ObjectAnimator 的 ofPropertyValuesHolder 方法,傳入作用對象以及要同時作用的 PropertyValuesHolder 即可執行。可以看到下面的代碼示例:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0F,200F); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("rotationX",0F,360F); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("translationY",0F,200F); ObjectAnimator.ofPropertyValuesHolder(mIvPicture,p1,p2,p3).setDuration(1000).start();
運行后可以發現,與之前的效果是相同的。
那既然兩種方法效果一樣,這樣相比之前有什么好處么?
AnimatorSet 屬性集合
playTogether 方法
我們其實還可以通過 AnimatorSet,來實現同樣的效果。這里我們調用了 set 的 playTogether 方法,使得這些方法同時執行:
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playTogether(animator1,animator2,animator3); set.setDuration(1000); set.start();
playSequentially方法
除了 playTogether 方法外,AnimatorSet 還提供了 playSequentially 方法,它可以使得動畫按順序執行。具體順序取決于調用時的參數順序。
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playSequentially(animator1,animator2,animator3); set.setDuration(1000); set.start();
play 與 with、after 方法
我們除了可以用上述方法來讓動畫按順序執行外,也可以通過 AnimatorSet 的 play、with、after、before 等方法相組合來控制動畫播放關系。
例如如下的代碼就可以實現先平移,再旋轉的效果
set.play(animator1).with(animator3); set.play(animator2).after(animator1);
動畫監聽事件
通過下面的代碼,我們可以實現按鈕按下后漸隱的效果。
mBtnPress.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ObjectAnimator animator = ObjectAnimator.ofFloat(mBtnPress,"alpha",1F,0F); animator.setDuration(1000); animator.start(); } });
但如果我們想要在動畫播放完成后再執行一些操作的話,又該如何實現呢?
AnimatorListener
一個AnimatorListener,需要實現四個方法,分別是:
它們的回調時機我們根據字面意思便可以理解。大部分時候,我們需要實現的是onAnimationEnd方法。
animator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } });
AnimatorListenerAdapter
如果每次監聽都需要實現這么多方法,未免太麻煩了一點。因此 Android 為我們提供了另一種方法來添加動畫的監聽事件:在添加 AnimatorListener 的時候,傳入 AnimatorListenerAdapter 即可。這樣我們就只需要實現自己需要的方法即可。
animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } });
ValueAnimator
簡介
ValueAnimator 本身不作用于任何一個屬性,也不提供任何一種動畫。它就是一個數值發生器,可以產生想要的各種數值。Android 系統為它提供了很多計算數值的方法,如 int、float 等等。我們也可以自己實現計算數值的方法。其實,在屬性動畫中,如何產生每一步的動畫效果,都是通過 ValueAnimator 計算出來的。
比如我們要實現一個從 0-100 的位移動畫。隨著動畫時間的持續,它產生的值也會從 0-100 遞增。通過這個 ValueAnimator 產生的值,再進行屬性的設置即可。
那么 ValueAnimator 究竟是如何產生這些值的呢?
由于 ValueAnimator 不作用于任何一個屬性,也不提供任何一種動畫。因此并沒有 ObjectAnimator 使用得廣泛。
實際上,ObjectAnimator 就是基于 ValueAnimator 進行的一次封裝。我們可以查看 ObjectAnimator 的源碼,會發現它繼承自 ValueAnimator,是它的一個子類。正是 ValueAnimator 產生的變化值,才使得 ObjectAnimator 可以將它應用于各個屬性。
使用方法
我們可以通過 ValueAnimator 的 ofXXX 產生一個 XXX 類型的值(如ofInt),然后為 ValueAnimator 添加一個更新的回調事件。在回調事件中,通過參數 animation 的 getAnimationValue() 方法,來獲取對應的 value。有了這個值,我們就可以實現我們所有想要的動畫效果。
比如此處就通過 ValueAnimator 實現了一個計時器的動畫效果。
ValueAnimator animator = ValueAnimator.ofInt(0,100); animator.setDuration(5000); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer value = (Integer) animation.getAnimatedValue(); mButton.setText(""+value); } }); animator.start();
自定義數值生成器
前面提到,ValueAnimator 可以創建自定義的數值生成器,做法就是調用 ValueAnimator 的 ofObject 方法,創建一個 TypeEvaluator 作為參數。之后我們可以通過重寫 TypeEvaluator 的 evaluate 方法,來按照自己的規則返回具體的值。
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public Object evaluate(float fraction, Object startValue, Object endValue) { //計算 return null; //返回值 } });
我們來看一下 evaluate 方法的幾個參數
通過這三個值,我們就可以經過計算產生所有我們想要的值。
其實,通過 TypeEvaluator,我們不光能產生普通的數據,還能結合泛型,我們還能定義更加復雜的數據:
我們可以在創建 TypeEvaluator 時指定具體類型,來達到更豐富的效果。比如這里就用到了一個名為 PointF 的數據類型:
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { //計算 return null; //返回值 } });
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。