轉載請註明出處!http://www.cnblogs.com/wondertwo/p/5295976.htmlhtml
提起 Android
動畫不少初學者就會一臉懵逼二階茫然,當初翻遍圖書館的一大堆入門書籍都找不到一本書在講 Android
動畫機制,好在一顆癡迷技術的心讓我自備燃料善始善終,最後總算弄明白了 Android
動畫究竟是個什麼鬼。其實咱們有木有常常用手機拍了不少漂亮照片之後,打開相冊,點擊更多,點擊自動播放,這些靜態的照片就會連貫的播放起來了有木有?這其實就是逐幀動畫,相似於動畫片的效果。是否是很簡單呢?關於Android動畫的分類我查了不少資料,最初只有兩種動畫即逐幀動畫(frame-by-frame animation
)和補間動畫(tweened animation
),補間動畫只須要開發者設置動畫的起始值和結束值,中間的動畫由系統自動幫咱們完成,下面要介紹的視圖動畫就屬於補間動畫。可是從Android 3.x開始谷歌引入了一種全新的動畫——屬性動畫,相對於視圖動畫只能給View對象設置動畫效果來講,屬性動畫要強大的太多,只要是一個Object對象屬性動畫都能爲其設置動畫屬性,無論這個對象能不能看得見,會不會與用戶產生交互。關於屬性動畫的用法會在下一篇博客中詳細介紹,下面的主要以講解視圖動畫爲主。視圖動畫即咱們常說的 View Animation
, 有四種效果以下:android
AlphaAnimation
);TranslateAnimation
);ScaleAnimation
);RotateAnimation
);能夠從Android api文檔看到視圖動畫 Add in api level 1
,算是 Android
動畫家族中的老臘肉了。那咱們就從視圖動畫的基本用法着手,一步步深刻學習!這裏先放上狂炫酷帥的QQ客戶端抖一抖動畫和3D旋轉&電視關閉畫面的自定義動畫,哈哈,這都是用視圖動畫作出來的效果哦!api
哈哈,上面的自定義動畫有木有驚豔到你呢?「每個宅男心中都藏着一個女神」,你看的沒錯!畫面中就是個人女神——張鈞甯。上面的動畫特效是在四種最基本的視圖動畫的基礎上稍加改進出來的,那麼四種基本的視圖動畫效果如何呢?app
分別對應着透明度變化(AlphaAnimation
),縮放(ScaleAnimation
),旋轉(RotateAnimation
),位移(TranslateAnimation
); View
動畫的四種變換效果對應着的 AlphaAnimation , ScaleAnimation , RotateAnimation , TranslateAnimation
這4個動畫類都繼承自 Animation
類,Animation
類是全部視圖動畫類的父類,後面講解的自定義動畫類其實也必須繼承 Animation
。ide
而且既能夠在代碼中動態的指定這四種動畫效果,也能夠在 xml
文件中定義, xml
文件中視圖動畫的目錄是 res/anim/file_name.xml
,與視圖動畫不一樣, xml
文件中屬性動畫的目錄是 res/animator/file_name.xml
,不過屬性動畫並不推薦在 xml 文件中定義,關於屬性動畫請關注個人下一篇博客哦 。xml
文件中視圖動畫代碼以下,透明度動畫對應標籤 <alpha>
,縮放動畫對應標籤 <scale>
,旋轉動畫對應標籤 <rotate>
,位移動畫對應標籤 <translate>
,根標籤 <set>
就表示一個動畫集合 AnimationSet
;shareInterpolator="true"
表示動畫集合中的全部動畫共享插值器,反之shareInterpolator="false"
表示不共享插值器,關於插值器會在第二篇博客的屬性動畫中詳細介紹。函數
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="true" > <!--透明度--> <alpha android:fromAlpha="0" android:toAlpha="1" /> <!--縮放--> <scale android:fromXScale="0.5f" android:fromYScale="1.5f" android:toXScale="0.5f" android:toYScale="1.5f" android:pivotX="100" android:pivotY="100" /> <!--位移--> <translate android:fromXDelta="0" android:toXDelta="0" android:fromYDelta="200" android:toYDelta="200" /> <!--旋轉--> <rotate android:fromDegrees="0" android:toDegrees="360" android:pivotX="200" android:pivotY="200" /> </set>
以上代碼標籤中的屬性值,其具體含義以下:post
除此以外,還有一些常見的屬性值,以下:學習
上面就是經過 xml
文件定義的 View
動畫,那怎麼應用上面的動畫呢?也很簡單,經過 View
對象在代碼中動態加載便可,代碼以下。值得注意的是,AnimationUtils.loadAnimation(this, R.anim.ani_view)
方法接收兩個參數,第一個是當前的上下文環境,第二個就是咱們經過 xml
定義的動畫啦。代碼以下:測試
ImageView ivAni = (ImageView) findViewById(R.id.iv_ani); Animation ani = AnimationUtils.loadAnimation(this, R.anim.ani_view); ivAni.startAnimation(ani);
OK那麼問題來了,怎樣直接經過代碼動態定義 View
動畫呢?也很簡單,先上代碼以下:動畫
AlphaAni
----透明度動畫代碼以下,相信你通過前面的部分已經能很容易就看懂這些代碼了,在 beginAnimation()
方法中,咱們在3000ms的時間內把一個 LinearLayout
對象 llAlpha
的透明度從0到1,即從徹底透明漸變到徹底不透明,而後在 onCreate()
方法中調用 beginAnimation()
方法就能以透明度漸變更畫的方式跳轉到 AlphaAni
:
package com.wondertwo.viewani; import android.app.Activity; import android.os.Bundle; import android.view.animation.AlphaAnimation; import android.widget.LinearLayout; import com.wondertwo.R; /** * AlphaAni----透明度動畫 * Created by wondertwo on 2016/3/11. */ public class AlphaAni extends Activity { private LinearLayout llAlpha; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_alpha); llAlpha = (LinearLayout) findViewById(R.id.ll_alpha); beginAnimation(); } // 啓動動畫 private void beginAnimation() { AlphaAnimation alpha = new AlphaAnimation(0, 1);// 0---->1從透明到不透明 alpha.setDuration(3000);// 設置動畫持續時間 llAlpha.startAnimation(alpha);// 啓動動畫 } }
ScaleAni
----縮放動畫代碼以下,與上面的透明度漸變更畫相似,經過 ctrl+左鍵
查看源碼能夠知道,在建立 ScaleAnimation
縮放動畫的對象的時候, ScaleAnimation(0, 2, 0, 2)
接受的四個參數分別是 ScaleAnimation(float fromX, float toX, float fromY, float toY)
:
package com.wondertwo.viewani; import android.app.Activity; import android.os.Bundle; import android.view.animation.ScaleAnimation; import android.widget.LinearLayout; import com.wondertwo.R; /** * ScaleAni----縮放動畫 * Created by wondertwo on 2016/3/11. */ public class ScaleAni extends Activity { private LinearLayout llScale; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_scale); llScale = (LinearLayout) findViewById(R.id.ll_scale); beginAnimation(); } // 啓動動畫 private void beginAnimation() { ScaleAnimation scale = new ScaleAnimation(0, 2, 0, 2); scale.setDuration(3000); llScale.startAnimation(scale); } }
RotateAni
----旋轉動畫代碼以下,表示把一個 View
對象從起始角度0旋轉到360度,後面的四個參數 RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f
表示以中心位置爲旋轉支點:
package com.wondertwo.viewani; import android.app.Activity; import android.os.Bundle; import android.view.animation.RotateAnimation; import android.widget.LinearLayout; import com.wondertwo.R; /** * RotateAni----旋轉動畫 * Created by wondertwo on 2016/3/11. */ public class RotateAni extends Activity { private LinearLayout llRotate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rotate); llRotate = (LinearLayout) findViewById(R.id.ll_rotate); beginAnimation(); } // 啓動動畫 private void beginAnimation() { RotateAnimation rotate = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotate.setDuration(3000); llRotate.startAnimation(rotate); } }
TranslateAni
----位移動畫代碼以下,表示把 View
對象從起始座標 (0, 0)
位移到 (200, 300)
,是否是很簡單呢:
package com.wondertwo.viewani; import android.app.Activity; import android.os.Bundle; import android.view.animation.TranslateAnimation; import android.widget.LinearLayout; import com.wondertwo.R; /** * TranslateAni----位移動畫 * Created by wondertwo on 2016/3/11. */ public class TranslateAni extends Activity { private LinearLayout llTranslate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_translate); llTranslate = (LinearLayout) findViewById(R.id.ll_translate); beginAnimation(); } // 啓動動畫 private void beginAnimation() { TranslateAnimation translate = new TranslateAnimation(0, 200, 0, 300); translate.setDuration(3000); llTranslate.startAnimation(translate); } }
趁熱打鐵,接下來正是掌握 View
動畫高級用法的好時機啦,所謂高級用法,其實也很簡單,就是把上面的四種基本效果進行任意的排列組合,而後設定重複次數、重複模式(經常使用的重複模式有順序、逆向等等),同時啓動或者延遲必定的時間啓動動畫!爲了更直觀感覺視圖動畫的高級用法,直接上圖請往下看,一種很酷炫的圖片旋轉飛入效果!
直接上代碼以下,看過代碼確定會以爲,不就是把上面介紹的四種動畫組合到一塊兒了嘛,事實上就是這麼簡單。
package com.wondertwo.viewani; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import android.widget.LinearLayout; import com.wondertwo.MainActivity; import com.wondertwo.R; /** * AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation四種視圖動畫的組合動畫 * Created by wondertwo on 2016/3/11. */ public class GroupAni extends Activity { private LinearLayout llGroup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_group); llGroup = (LinearLayout) findViewById(R.id.ll_group); beginAnimation(); } // 啓動組合動畫 private void beginAnimation() { // 建立動畫集合 AnimationSet aniSet = new AnimationSet(false); // 透明度動畫 AlphaAnimation alpha = new AlphaAnimation(0, 1); alpha.setDuration(4000); aniSet.addAnimation(alpha); // 旋轉動畫 RotateAnimation rotate = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotate.setDuration(4000); aniSet.addAnimation(rotate); // 縮放動畫 ScaleAnimation scale = new ScaleAnimation(1.5f, 0.5f, 1.5f, 0.5f); scale.setDuration(4000); aniSet.addAnimation(scale); // 位移動畫 TranslateAnimation translate = new TranslateAnimation(0, 160, 0, 240); translate.setDuration(4000); aniSet.addAnimation(translate); // 動畫監聽 aniSet.setAnimationListener(new Animation.AnimationListener() { // 動畫開始 @Override public void onAnimationStart(Animation animation) { } // 動畫結束,通常在這裏實現頁面跳轉邏輯 @Override public void onAnimationEnd(Animation animation) { // 動畫結束後,跳轉到主頁面 startActivity(new Intent(GroupAni.this, MainActivity.class)); } // 動畫重複 @Override public void onAnimationRepeat(Animation animation) { } }); // 把動畫設置給llGroup llGroup.startAnimation(aniSet); } }
惟一不一樣的是,咱們此次是把四個 View
動畫裝進了一個動畫集合(AnimationSet
)中,至於動畫集合,你就把他當作普通的 Set
集合使用就好,建立動畫集合時傳入的參數 false
表示動畫集合中裝入的和四個 View
動畫不共享插值器。到這裏你已經學會 View
動畫了,可是後面還有更高級用法呢!
當你看完上面的 View
動畫,自定義 View
動畫對你來講已經不在話下,我準備的兩個 demo
你確定很期待,分別是:模仿QQ客戶端的抖一抖特效,和電視畫面關閉&3D旋轉,效果以下:
模仿QQ客戶端的抖一抖特效,先上代碼!
package com.wondertwo.qqTremble; import android.view.animation.Animation; import android.view.animation.Transformation; /** * QQ抖一抖特效的自定義View動畫實現 * Created by wondertwo on 2016/3/17. */ public class QQTrembleAni extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { t.getMatrix().setTranslate( (float) Math.sin(interpolatedTime * 50) * 8, (float) Math.sin(interpolatedTime * 50) * 8 );// 50越大頻率越高,8越小振幅越小 super.applyTransformation(interpolatedTime, t); } }
上面這段代碼就是咱們自定義的QQ抖一抖動畫了,全部的自定義動畫都須要繼承 android.view.animation.Animation
抽象類,而後重寫 initialize()
和 applyTransformation()
這兩個方法,在 initialize()
方法中對一些變量進行初始化,在 applyTransformation()
方法中經過矩陣修改動畫數值,從而控制動畫的實現過程,這也是自定義動畫的核心。 applyTransformation(float interpolatedTime, Transformation t)
方法在動畫的執行過程當中會不斷地調用,能夠看到接收的兩個參數分別是 float interpolatedTime
表示當前動畫進行的時間與動畫總時間(通常在 setDuration()
方法中設置)的比值,從0逐漸增大到1; Transformation t
傳遞當前動畫對象,通常能夠經過代碼 android.graphics.Matrix matrix = t.getMatrix()
得到 Matrix
矩陣對象,再設置 Matrix
對象,通常要用到 interpolatedTime
參數,以此達到控制動畫實現的結果。能夠看到在上面的代碼中 t.getMatrix().setTranslate((float) Math.sin(interpolatedTime * 50) * 8, (float) Math.sin(interpolatedTime * 50) * 8)
設置了 Matrix
對象的 Translate
,傳入的參數是一個正弦函數值,這個值是經過 interpolatedTime
參數計算出來的,這樣就實現了動畫在x,y軸兩個方向上的來回抖動效果。
下面是QQ抖一抖動畫的測試類 Activity
,代碼以下:
package com.wondertwo.qqTremble; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.RelativeLayout; import com.wondertwo.R; /** * 模仿QQ抖一抖效果的測試類 * Created by wondertwo on 2016/3/17. */ public class QQTrembleTest extends Activity { private RelativeLayout rlTremble; private Button btnTremble; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qq_tremble); rlTremble = (RelativeLayout) findViewById(R.id.rl_tremble); btnTremble = (Button) findViewById(R.id.btn_tremble); // 建立抖一抖動畫對象 final QQTrembleAni tremble = new QQTrembleAni(); tremble.setDuration(800);// 持續時間800ms,持續時間越短頻率越高 tremble.setRepeatCount(2);// 重複次數,不包含第一次 // 設置按鈕點擊監聽 btnTremble.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 啓動抖一抖效果 rlTremble.startAnimation(tremble); } }); } }
接着咱們再看一個酷炫的自定義動畫,相似電視機關機畫面和圖片3D旋轉,效果以下!
直接上代碼,電視關機畫面效果動畫 TVCloseAni
以下:
package com.wondertwo.custom; import android.graphics.Matrix; import android.view.animation.Animation; import android.view.animation.Transformation; /** * 經過矩陣變換模擬電視關閉效果,使圖片的縱向比例不斷縮小 * Created by wondertwo on 2016/3/13. */ public class TVCloseAni extends Animation { private int mCenterWidth, mCenterHeight; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); // 設置默認時長 setDuration(4000); // 保持動畫的結束狀態 setFillAfter(true); // 設置默認插值器 // setInterpolator(new BounceInterpolator());// 回彈效果的插值器 mCenterWidth = width / 2; mCenterHeight = height /2; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); final Matrix matrix = t.getMatrix(); matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight); } }
圖片3D旋轉效果動畫代碼以下:
package com.wondertwo.custom; import android.graphics.Camera; import android.graphics.Matrix; import android.view.animation.Animation; import android.view.animation.BounceInterpolator; import android.view.animation.Transformation; /** * * Created by wondertwo on 2016/3/13. */ public class CustomAni extends Animation { private int mCenterWidth, mCenterHeight; private Camera mCamera = new Camera(); private float mRotateY = 0.0f; // 通常在此方法初始化一些動畫相關的變量和值 @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); // 設置默認時長 setDuration(4000); // 保持動畫的結束狀態 setFillAfter(true); // 設置默認插值器 setInterpolator(new BounceInterpolator());// 回彈效果的插值器 mCenterWidth = width / 2; mCenterHeight = height /2; } // 暴露接口設置旋轉角度 public void setRotateY(float rotateY) { mRotateY = rotateY; } // 自定義動畫的核心,在動畫的執行過程當中會不斷回調此方法,而且每次回調interpolatedTime值都在不斷變化(0----1) @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); final Matrix matrix = t.getMatrix(); mCamera.save(); // 使用Camera設置Y軸方向的旋轉角度 mCamera.rotateY(mRotateY * interpolatedTime); // 將旋轉變化做用到matrix上 mCamera.getMatrix(matrix); mCamera.restore(); // 經過pre方法設置矩陣做用前的偏移量來改變旋轉中心 matrix.preTranslate(mCenterWidth, mCenterHeight);// 在旋轉以前開始位移動畫 matrix.postTranslate(-mCenterWidth, -mCenterHeight);// 在旋轉以後開始位移動畫 } }
下面是電視機關機畫面和圖片3D旋轉動畫的測試類, CustomAniTest
代碼以下!
package com.wondertwo.custom; import android.app.Activity; import android.os.Bundle; import android.view.View; import com.wondertwo.R; /** * 自定義動畫測試類 * Created by wondertwo on 2016/3/13. */ public class CustomAniTest extends Activity { private boolean flag = true;// 標記位,輪換展現兩種自定義動畫 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_ani); } /** * 設置按鈕點擊事件 */ public void startCustomAni(View view) { if (flag) { TVCloseAni tvAni = new TVCloseAni(); view.startAnimation(tvAni); // 重置標記位 flag = false; } else { CustomAni customAni = new CustomAni(); customAni.setRotateY(30); view.startAnimation(customAni); // 重置標記位 flag = true; } } }
惟一不一樣的是在上面3D旋轉自定義動畫中,咱們引入了 Camera
的概念, android.graphics.Camera
中的 Camera
類封裝了 openGL
的3D動畫,所以能夠經過 Camera
類實現不少酷炫的3D動畫效果。關於Android中矩陣Matrix的概念,在不少地方都會用到,好比圖片處理,動畫變換等等地方,這裏我就不仔細展開啦!貼上http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code,看完你確定能明白矩陣的巨大威力啦,這裏感謝原做者!
在最後附上淺析Android動畫系列的三篇文章:
若是以爲不錯,請繼續關注哦!下一篇將繼續介紹Android屬性動畫哈!