自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

動畫 ViewPropertyAnimator 使用詳解和原理分析

開發(fā) 前端
平常所做的動畫大部分是針對View的,而View經常會需要集中動畫混合在一起做,因此提供了一個ViewPropertyAnimator類來快速的實現(xiàn)多個動畫的混合。

[[440662]]

本文轉載自微信公眾號「Android開發(fā)編程」,作者Android開發(fā)編程。轉載本文請聯(lián)系Android開發(fā)編程公眾號。

前言

平常所做的動畫大部分是針對View的,而View經常會需要集中動畫混合在一起做,因此提供了一個ViewPropertyAnimator類來快速的實現(xiàn)多個動畫的混合;

ViewPropertyAnimator從名字就可以看出是專用于View的屬性動畫,在API12被提供;

ViewPropertyAnimator專用于操作View動畫,語法更加簡潔,使用更加方便;

今天就來看看怎么用;

一、ViewPropertyAnimator使用詳解

1、獲取對象

ViewPropertyAnimator 沒有構造函數(shù),通過View.animate()方法可以方便的獲取;ViewPropertyAnimator 對象,此時獲取的動畫對象就專用于操作當前view;

  1. public ViewPropertyAnimator animate() { 
  2.     if (mAnimator == null) { 
  3.         mAnimator = new ViewPropertyAnimator(this); 
  4.     } 
  5.     return mAnimator; 

2、基本函數(shù)屬性介紹

  • alpha(float value) 設置View的透明度,value最終值;
  • alphaBy(float value) 設置View的透明度,value是在view當前值的基礎上的偏移量;rotation(float value):旋轉View,正值順時針,負值逆時針,value最終值;
  • rotationBy(float value):旋轉,在當前值得基礎上偏移量;
  • rotationX(float value):繞x軸旋轉;
  • rotationXBy(float value):當View旋轉的基礎上以value為偏移量繞X軸旋轉;
  • rotationY(float value):繞Y軸旋轉;
  • rotationYBy(float value):在當前旋轉的基礎上繞Y軸旋轉;
  • scaleX(float value):縮放view的X軸方向上的大小;
  • scaleXBy(float value):當前View縮放的基礎上,在X軸方向上對view進行縮放;
  • scaleY(float value):縮放view的Y軸方向上的大小;
  • scaleYBy(float value):當前View縮放的基礎上,對view的Y軸方向進行縮放;
  • translationX(float value):沿X軸方向平移,value大于0,X軸正方向;
  • translationXBy(float value):帶有偏移量的平移;
  • translationY(float value):沿Y軸方向平移,value大于0,沿Y軸正方向平移;
  • translationYBy(float value) :在當前值的基礎上,在Y軸方向上平移;
  • x(float value):在當前值的基礎上,修改view 的X坐標;
  • xBy(float value):在當前值的基礎上,修改view 的X坐標;
  • y(float value):在當前值的基礎上,修改View的Y的坐標;
  • yBy(float value):在當前值的基礎上,修改View的Y的坐標;
  • z(float value):在當前值的基礎上,修改View的Z的坐標;
  • zBy(float value):在當前值的基礎上,修改View的Z的坐標;

3、基本使用

常用方法

  1. btnShow.animate() 
  2.                         .setDuration(5000) 
  3.                         //透明度 
  4.                         .alpha(0) 
  5.                         .alphaBy(0) 
  6.                         //旋轉 
  7.                         .rotation(360) 
  8.                         .rotationBy(360) 
  9.                         .rotationX(360) 
  10.                         .rotationXBy(360) 
  11.                         .rotationY(360) 
  12.                         .rotationYBy(360) 
  13.                         //縮放 
  14.                         .scaleX(1) 
  15.                         .scaleXBy(1) 
  16.                         .scaleY(1) 
  17.                         .scaleYBy(1) 
  18.                         //平移 
  19.                         .translationX(100) 
  20.                         .translationXBy(100) 
  21.                         .translationY(100) 
  22.                         .translationYBy(100) 
  23.                         .translationZ(100) 
  24.                         .translationZBy(100) 
  25.                         //更改在屏幕上的坐標 
  26.                         .x(10) 
  27.                         .xBy(10) 
  28.                         .y(10) 
  29.                         .yBy(10) 
  30.                         .z(10) 
  31.                         .zBy(10) 
  32.                         //監(jiān)聽及其他設置 
  33.                         .setInterpolator(new BounceInterpolator()) 
  34.                         .setStartDelay(1000) 
  35.                         .setListener(new Animator.AnimatorListener() { 
  36.                             @Override 
  37.                             public void onAnimationStart(Animator animation) { 
  38.                             } 
  39.                             @Override 
  40.                             public void onAnimationEnd(Animator animation) { 
  41.                             } 
  42.                             @Override 
  43.                             public void onAnimationCancel(Animator animation) { 
  44.                             } 
  45.                             @Override 
  46.                             public void onAnimationRepeat(Animator animation) { 
  47.                             } 
  48.                         }) 
  49.                         .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  50.                             @Override 
  51.                             public void onAnimationUpdate(ValueAnimator animation) { 
  52.                             } 
  53.                         }) 
  54.                         .withEndAction(new Runnable() { 
  55.                             @Override 
  56.                             public void run() { 
  57.                                 Log.i(TAG, "run: end"); 
  58.                             } 
  59.                         }) 
  60.                         .withStartAction(new Runnable() { 
  61.                             @Override 
  62.                             public void run() { 
  63.                                 Log.i(TAG, "run: start"); 
  64.                             } 
  65.                         }) 
  66.                         .start(); 

4、添加監(jiān)聽

  • setUpdateListener:添加動畫屬性變化監(jiān)聽
  • setListener:添加動畫狀態(tài)監(jiān)聽
  1. ViewPropertyAnimator viewPropertyAnimator = gongxiang.animate().setDuration(3000).x(700).y(700).rotation(270).alpha(0.5f).setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  2.     @Override 
  3.     public void onAnimationUpdate(ValueAnimator animation) { 
  4.         ); 
  5.     } 
  6. }).setListener(new AnimatorListenerAdapter() { 
  7.     @Override 
  8.     public void onAnimationCancel(Animator animation) { 
  9.         super.onAnimationCancel(animation); 
  10.     } 
  11.     @Override 
  12.     public void onAnimationEnd(Animator animation) { 
  13.         super.onAnimationEnd(animation); 
  14.         System.out.println("=========onAnimationEnd======="); 
  15.     } 
  16.     @Override 
  17.     public void onAnimationRepeat(Animator animation) { 
  18.         super.onAnimationRepeat(animation); 
  19.     } 
  20.     @Override 
  21.     public void onAnimationStart(Animator animation) { 
  22.         super.onAnimationStart(animation); 
  23.         System.out.println("=========onAnimationStart======="); 
  24.     } 
  25.     @Override 
  26.     public void onAnimationPause(Animator animation) { 
  27.         super.onAnimationPause(animation); 
  28.     } 
  29.     @Override 
  30.     public void onAnimationResume(Animator animation) { 
  31.         super.onAnimationResume(animation); 
  32.     } 
  33. }); 

二、基本原理

1、執(zhí)行動畫基本步驟如下

  • 通過test.animate()獲取ViewPropertyAnimator對象;
  • 調用alpha、translationX等方法,返回當前ViewPropertyAnimator對象,可以繼續(xù)鏈式調用;
  • alpha、translationX等方法內部最終調用animatePropertyBy(int constantName, float startValue, float byValue)方法;
  • 在animatePropertyBy方法中則會將alpha、translationX等方法的操作封裝成NameVauleHolder,并將每個NameValueHolder對象添加到準備列表mPendingAnimations中;
  • animatePropertyBy方法啟動mAnimationStarter,調用startAnimation,開始動畫;
  • startAnimation方法中會創(chuàng)建一個ValueAnimator對象設置內部監(jiān)聽器;AnimatorEventListener,并將mPendingAnimations和要進行動畫的屬性名稱封裝成一個PropertyBundle對象,最后mAnimatorMap保存當前Animator和對應的PropertyBundle對象,該Map將會在animatePropertyBy方法和Animator監(jiān)聽器mAnimatorEventListener中使用,啟動動畫;
  • 在動畫的監(jiān)聽器的onAnimationUpdate方法中設置所有屬性的變化值,并通過RenderNode類優(yōu)化繪制性能,最后刷新界面;

2、startAnimation()的源碼

  1. /** 
  2.  * Starts the underlying Animator for a set of properties. We use a single animator that 
  3.  * simply runs from 0 to 1, and then use that fractional value to set each property 
  4.  * value accordingly. 
  5.  */ 
  6. private void startAnimation() { 
  7.     if (mRTBackend != null && mRTBackend.startAnimation(this)) { 
  8.         return
  9.     } 
  10.     mView.setHasTransientState(true); 
  11.     //創(chuàng)建ValueAnimator 
  12.     ValueAnimator animator = ValueAnimator.ofFloat(1.0f); 
  13.     //clone一份mPendingAnimations賦值給nameValueList 
  14.     ArrayList<NameValuesHolder> nameValueList = 
  15.             (ArrayList<NameValuesHolder>) mPendingAnimations.clone(); 
  16.      //賦值完后清空 
  17.     mPendingAnimations.clear(); 
  18.     //用于標識要執(zhí)行動畫的屬性 
  19.     int propertyMask = 0; 
  20.     int propertyCount = nameValueList.size(); 
  21.     //遍歷所有nameValuesHolder,取出其屬性名稱mNameConstant, 
  22.     //執(zhí)行"|"操作并最終賦值propertyMask 
  23.     for (int i = 0; i < propertyCount; ++i) { 
  24.         NameValuesHolder nameValuesHolder = nameValueList.get(i); 
  25.         propertyMask |= nameValuesHolder.mNameConstant; 
  26.     } 
  27.     //創(chuàng)建PropertyBundle,并添加到mAnimatorMap中 
  28.     mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList)); 
  29.     if (mPendingSetupAction != null) { 
  30.         //設置硬件加速 
  31.         mAnimatorSetupMap.put(animator, mPendingSetupAction); 
  32.         mPendingSetupAction = null
  33.     } 
  34.     if (mPendingCleanupAction != null) { 
  35.        //移除硬件加速 
  36.         mAnimatorCleanupMap.put(animator, mPendingCleanupAction); 
  37.         mPendingCleanupAction = null
  38.     } 
  39.     if (mPendingOnStartAction != null) { 
  40.         //設置開始的動畫(監(jiān)聽器的開始方法中調用) 
  41.         mAnimatorOnStartMap.put(animator, mPendingOnStartAction); 
  42.         mPendingOnStartAction = null
  43.     } 
  44.     if (mPendingOnEndAction != null) { 
  45.         //設置結束后要進行的下一個動畫(監(jiān)聽器的結束方法中調用) 
  46.         mAnimatorOnEndMap.put(animator, mPendingOnEndAction); 
  47.         mPendingOnEndAction = null
  48.     } 
  49.     //添加內部監(jiān)聽器 
  50.     animator.addUpdateListener(mAnimatorEventListener); 
  51.     animator.addListener(mAnimatorEventListener); 
  52.     //判斷是否延長開始 
  53.     if (mStartDelaySet) { 
  54.         animator.setStartDelay(mStartDelay); 
  55.     } 
  56.     //執(zhí)行動畫的實現(xiàn) 
  57.     if (mDurationSet) { 
  58.         animator.setDuration(mDuration); 
  59.     } 
  60.     //設置插值器 
  61.     if (mInterpolatorSet) { 
  62.         animator.setInterpolator(mInterpolator); 
  63.     } 
  64.     //開始執(zhí)行動畫 
  65.     animator.start(); 
  • 創(chuàng)建Animator,變化值從0到1,設置內部監(jiān)聽器mAnimatorEventListener;
  • clone一份mPendingAnimations列表,并計算屬性值標記propertyMask,封裝成PropertyBundle對象;
  • 使用mAnimatorMap保存當前Animator和對應的PropertyBundle對象;
  • 該Map將會在animatePropertyBy方法和Animator監(jiān)聽器mAnimatorEventListener中使用;
  • 啟動animator動畫;

2、PropertyBundle

  1. private static class PropertyBundle { 
  2.         int mPropertyMask; 
  3.         ArrayList<NameValuesHolder> mNameValuesHolder; 
  4.         PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) { 
  5.             mPropertyMask = propertyMask; 
  6.             mNameValuesHolder = nameValuesHolder; 
  7.         } 
  8.         boolean cancel(int propertyConstant) { 
  9.             if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) { 
  10.                 int count = mNameValuesHolder.size(); 
  11.                 for (int i = 0; i < count; ++i) { 
  12.                     NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i); 
  13.                     if (nameValuesHolder.mNameConstant == propertyConstant) { 
  14.                         mNameValuesHolder.remove(i); 
  15.                         mPropertyMask &= ~propertyConstant; 
  16.                         return true
  17.                     } 
  18.                 } 
  19.             } 
  20.             return false
  21.         } 
  22.     } 

PropertyBundle:內部類,存放著將要執(zhí)行的動畫的屬性集合信息,每次調用animator.start();

都會將存放在mPendingAnimations的clone一份存入PropertyBundle的內部變量mNameValuesHolder中,然后再將遍歷mPendingAnimations中的NameValueHolder類,取出要執(zhí)行的屬性進行”|”操作;

最后記錄成一個mPropertyMask的變量,存放在PropertyBundle中,PropertyBundle就是最終要執(zhí)行動畫的全部屬性的封裝類;

3、AnimatorEventListener

  1. private class AnimatorEventListener 
  2.             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { 
  3. ... 
  4. ... 

ViewPropertyAnimator內部的監(jiān)聽器:這個類實現(xiàn)了Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener接口;

這個類還有一個onAnimationUpdate()的監(jiān)聽方法,它是動畫執(zhí)行的關鍵所在;

4、mAnimatorMap

  1. private HashMap<Animator, PropertyBundle> mAnimatorMap = 
  2.         new HashMap<Animator, PropertyBundle>(); 
  • mAnimatorMap:存放PropertyBundle類的Map,這個Map中存放的是正在執(zhí)行的動畫的PropertyBundle,這個PropertyBundle包含這本次動畫的所有屬性的信息;
  • 最終在AnimatorEventListener的onAnimationUpdate()方法中會通過這個map獲取相應的屬性,然后不斷更新每幀的屬性值以達到動畫效果;
  • 通過前面對animatePropertyBy方法的分析,我們可以知道該Map會保證當前只有一個Animator對象對該View的屬性進行操作,不會存在兩個Animator在操作同一個屬性;

5、onAnimationUpdate

  1. @Override 
  2.         public void onAnimationUpdate(ValueAnimator animation) { 
  3.         //取出當前Animator對應用propertyBundle對象 
  4.             PropertyBundle propertyBundle = mAnimatorMap.get(animation); 
  5.             if (propertyBundle == null) { 
  6.                 // Shouldn't happen, but just to play it safe 
  7.                 return
  8.             } 
  9.         //是否開啟了硬件加速 
  10.             boolean hardwareAccelerated = mView.isHardwareAccelerated(); 
  11.             // alpha requires slightly different treatment than the other (transform) properties. 
  12.             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation 
  13.             // logic is dependent on how the view handles an internal call to onSetAlpha(). 
  14.             // We track what kinds of properties are setand how alpha is handled when it is 
  15.             // setand perform the invalidation steps appropriately. 
  16.             boolean alphaHandled = false
  17.             if (!hardwareAccelerated) { 
  18.                 mView.invalidateParentCaches(); 
  19.             } 
  20.             //取出當前的估算值(插值器計算值) 
  21.             float fraction = animation.getAnimatedFraction(); 
  22.             int propertyMask = propertyBundle.mPropertyMask; 
  23.             if ((propertyMask & TRANSFORM_MASK) != 0) { 
  24.                 mView.invalidateViewProperty(hardwareAccelerated, false); 
  25.             } 
  26.             //取出所有要執(zhí)行的屬性動畫的封裝對象NameValuesHolder 
  27.             ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder; 
  28.             if (valueList != null) { 
  29.                 int count = valueList.size(); 
  30.                 //遍歷所有NameValuesHolder,計算變化值,并設置給對應的屬性 
  31.                 for (int i = 0; i < count; ++i) { 
  32.                     NameValuesHolder values = valueList.get(i); 
  33.                     float value = values.mFromValue + fraction * values.mDeltaValue; 
  34.                     if (values.mNameConstant == ALPHA) { 
  35.                         alphaHandled = mView.setAlphaNoInvalidation(value); 
  36.                     } else { 
  37.                         setValue(values.mNameConstant, value); 
  38.                     } 
  39.                 } 
  40.             } 
  41.             if ((propertyMask & TRANSFORM_MASK) != 0) { 
  42.                 if (!hardwareAccelerated) { 
  43.                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation 
  44.                 } 
  45.             } 
  46.             // invalidate(falsein all cases except if alphaHandled gets set to true 
  47.             // via the call to setAlphaNoInvalidation(), above 
  48.             if (alphaHandled) { 
  49.                 mView.invalidate(true); 
  50.             } else { 
  51.                 mView.invalidateViewProperty(falsefalse); 
  52.             } 
  53.             if (mUpdateListener != null) { 
  54.                 mUpdateListener.onAnimationUpdate(animation); 
  55.             } 
  56.         } 

取出當前Animator對應用propertyBundle對象并獲取當前的估算值(插值器計算值),用于后續(xù)動畫屬性值的計算;

從propertyBundle取出要進行動畫的屬性列表 ArrayList valueList;

遍歷所有NameValuesHolder,計算變化值,并通過setValue設置給對應的屬性,如果是ALPHA,則會特殊處理一下,最終形成動畫效果;

總結

 

年底了,有疫情有裁員,大家要努力,一起加油

 

責任編輯:武曉燕 來源: Android開發(fā)編程
相關推薦

2025-01-16 14:03:35

Redis

2021-12-06 14:52:08

動畫Android補間動畫

2021-11-29 06:57:50

App使用屬性

2021-12-02 18:05:21

Android Interpolato動畫

2009-07-09 14:01:22

JVM工作原理

2010-09-26 08:50:11

JVM工作原理

2021-08-09 20:29:27

Android沉浸式狀態(tài)欄

2017-05-17 08:51:39

WebView分析應用

2021-06-01 09:27:52

視頻動畫Remotion

2020-01-06 10:58:18

JvmGC機制虛擬機

2015-08-21 09:56:17

Java內存分析MAT使用

2016-12-13 22:51:08

androidmultidex

2019-09-03 15:36:58

ApacheTomcat配置

2020-07-08 13:46:27

ApacheTomcat配置

2024-12-19 11:00:00

TCP網(wǎng)絡通信粘包

2025-02-27 00:10:19

2024-06-27 08:26:10

LooperAndroid內存

2020-09-28 15:00:19

Linux容器虛擬化

2023-02-02 09:13:12

Hive壓縮使用性能分析

2011-08-15 22:10:08

Oracle性能分析工
點贊
收藏

51CTO技術棧公眾號