本猿自詡Android小白,天然呆穀粉米粉,愛開源,更愛漂亮妹紙((^o^)/~來跟我一起唱:原諒我一生放蕩不羈愛自由~~~請自行腦補掌聲三分鐘^O^);好了好了說人話:本猿中南大學大三狗一個,每天最快樂的時光都與14寸的DeskTop為伴,曾經我是一個熱愛並略懂Java和Android的小白,現在我是一個熱愛並熟悉Java和Android的小白,就這樣!聊技術談夢想歡迎私信 @哈皮小猿_wondertwo
檢視動畫的基本用法
提起 Android
動畫很多初學者就會一臉懵逼二階茫然,當初翻遍圖書館的一大堆入門書籍都找不到一本書在講 Android
動畫機制,好在一顆痴迷技術的心讓我自備燃料有始有終,最後總算弄明白了 Android
動畫到底是個什麼鬼。其實我們有木有經常用手機拍了很多漂亮照片以後,開啟相簿,點選更多,點選自動播放,這些靜態的照片就會連貫的播放起來了有木有?這其實就是逐幀動畫,類似於動畫片的效果。是不是很簡單呢?關於Android動畫的分類我查了很多資料,最初只有兩種動畫即逐幀動畫(frame-by-frame animation
)和補間動畫(tweened animation
),補間動畫只需要開發者設定動畫的起始值和結束值,中間的動畫由系統自動幫我們完成,下面要介紹的檢視動畫就屬於補間動畫。但是從Android 3.x開始谷歌引入了一種全新的動畫——屬性動畫,相對於檢視動畫只能給View物件設定動畫效果來說,屬性動畫要強大的太多,只要是一個Object物件屬性動畫都能為其設定動畫屬性,不管這個物件能不能看得見,會不會與使用者產生互動。關於屬性動畫的用法會在下一篇部落格中詳細介紹,下面的主要以講解檢視動畫為主。檢視動畫即我們常說的 View Animation
, 有四種效果如下:
- 透明度變化(
AlphaAnimation
); - 位移(
TranslateAnimation
); - 縮放(
ScaleAnimation
); - 旋轉(
RotateAnimation
);
可以從Android api文件看到檢視動畫 Add in api level 1
,算是 Android
動畫家族中的老臘肉了。那我們就從檢視動畫的基本用法著手,一步步深入學習!這裡先放上狂炫酷帥的QQ客戶端抖一抖動畫和3D旋轉&電視關閉畫面的自定義動畫,哈哈,這都是用檢視動畫做出來的效果哦!
哈哈,上面的自定義動畫有木有驚豔到你呢?“每一個宅男心中都藏著一個女神”,你看的沒錯!畫面中就是我的女神——張鈞甯。上面的動畫特效是在四種最基本的檢視動畫的基礎上稍加改進出來的,那麼四種基本的檢視動畫效果如何呢?
分別對應著透明度變化(AlphaAnimation
),縮放(ScaleAnimation
),旋轉(RotateAnimation
),位移(TranslateAnimation
); View
動畫的四種變換效果對應著的 AlphaAnimation , ScaleAnimation , RotateAnimation , TranslateAnimation
這4個動畫類都繼承自 Animation
類,Animation
類是所有檢視動畫類的父類,後面講解的自定義動畫類其實也必須繼承 Animation
。
並且既可以在程式碼中動態的指定這四種動畫效果,也可以在 xml
檔案中定義, xml
檔案中檢視動畫的目錄是 res/anim/file_name.xml
,與檢視動畫不同, xml
檔案中屬性動畫的目錄是 res/animator/file_name.xml
,不過屬性動畫並不推薦在 xml 檔案中定義,關於屬性動畫請關注我的下一篇部落格哦 。xml
檔案中檢視動畫程式碼如下,透明度動畫對應標籤 ,縮放動畫對應標籤
,旋轉動畫對應標籤
,位移動畫對應標籤
,根標籤
就表示一個動畫集合
AnimationSet
;shareInterpolator="true"
表示動畫集合中的所有動畫共享插值器,反之shareInterpolator="false"
表示不共享插值器,關於插值器會在第二篇部落格的屬性動畫中詳細介紹。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<code> <?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> </code> |
以上程式碼標籤中的屬性值,其具體含義如下:
- alpha
- fromAlpha —- 透明度起始值,0表示完全透明
- toAlpha —- 透明度最終值,1表示不透明
- scale
- fromXScale —- 水平方向縮放的起始值,比如0
- fromYScale —- 豎直方向縮放的起始值,比如0
- toXScale —- 水平方向縮放的結束值,比如2
- toYScale —- 豎直方向縮放的結束值,比如2
- pivotX —- 縮放支點的x座標
- pivotY —- 縮放支點的y座標(支點可以理解為縮放的中心點,縮放過程中這點的座標是不變的;支點預設在中心位置)
- translate
- fromXDelta —- x起始值
- toXDelta —- x結束值
- fromYDelta —- y起始值
- toYDelta —- y結束值
- rotate
- fromDegrees —- 旋轉起始角度
- toDegrees —- 旋轉結束角度
除此之外,還有一些常見的屬性值,如下:
- android:duration —- 動畫的持續時間
- android:fillAfter —- true表示保持動畫結束時的狀態,false表示不保持
上面就是通過 xml
檔案定義的 View
動畫,那怎麼應用上面的動畫呢?也很簡單,通過 View
物件在程式碼中動態載入即可,程式碼如下。值得注意的是,AnimationUtils.loadAnimation(this, R.anim.ani_view)
方法接收兩個引數,第一個是當前的上下文環境,第二個就是我們通過 xml
定義的動畫啦。程式碼如下:
1 2 3 |
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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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)
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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
表示以中心位置為旋轉支點:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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)
,是不是很簡單呢:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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
動畫高階用法的好時機啦,所謂高階用法,其實也很簡單,就是把上面的四種基本效果進行任意的排列組合,然後設定重複次數、重複模式(常用的重複模式有順序、逆向等等),同時啟動或者延遲一定的時間啟動動畫!為了更直觀感受檢視動畫的高階用法,直接上圖請往下看,一種很酷炫的圖片旋轉飛入效果!
直接上程式碼如下,看過程式碼肯定會覺得,不就是把上面介紹的四種動畫組合到一起了嘛,事實上就是這麼簡單。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
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
動畫,自定義 View
動畫對你來說已經不在話下,我準備的兩個 demo
你肯定很期待,分別是:模仿QQ客戶端的抖一抖特效,和電視畫面關閉&3D旋轉,效果如下:
模仿QQ客戶端的抖一抖特效,先上程式碼!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
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旋轉效果動畫程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
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
程式碼如下!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
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動畫(一),View動畫高階例項探究 http://www.cnblogs.com/wondertwo/p/5295976.html
- 淺析Android動畫(二),屬性動畫與高階例項探究 http://www.cnblogs.com/wondertwo/p/5312482.html
- 淺析Android動畫(三),自定義Interpolator與TypeEvaluator http://www.cnblogs.com/wondertwo/p/5327586.html
如果覺得不錯,請繼續關注哦!下一篇將繼續介紹Android屬性動畫哈!