編輯:關於android開發
在Android開發中經常會碰到動畫,看到別的應用有很酷炫的應用時,總是想怎麼去實現,但是每次都是發現感覺是知道怎麼做的,實際做起來還是無從下手的感覺,究其原因還是
Android動畫方面的知識不全面,這幾天利用空閒時間研究了下Android動畫知識,當作學習日記,大家也好有所借鑒。
Android主要分三類動畫:Tween Animation、Frame Animation、Property Animation。
其中Tween Animation、Frame Animation是在Android是在Android3.0之前就有的動畫技術,後來由於動畫需求越來越高,Tween Animation、Frame Animation已經滿足不了應用對於動畫效果的需求了,於是在Android3.0之後,谷歌又增加了新的動畫Property Animation。下面對這三種動畫逐個介紹。
一、Tween Animation
中文亦叫補間動畫,它是通過平移、旋轉、縮放以及修改透明度來達到動畫效果的,原理是給出兩個關鍵幀,通過一些算法將給定屬性值在給定時間內在兩個關鍵幀間漸變。這裡我們只關心動畫的使用,不關注它的代碼實現。Tween Animation基於Animation類擴展,有以下幾個Tween Animation類:TranslateAnimation(平移)、AlphaAnimation(透明度)、ScaleAnimation(縮 放)、RotateAnimation(旋轉)。
TranslateAnimation使用方法如下:
private TranslateAnimation mTranslateAnimation; //這四個參數含義分別是當前View x起點坐標、x終點坐標、y起點坐標、y終點坐標 mTranslateAnimation = new TranslateAnimation(0, 200, 0, 0); //動畫持續時間 mTranslateAnimation.setDuration(2000); //重復次數 mTranslateAnimation.setRepeatCount(1); //動畫執行模式 mTranslateAnimation.setRepeatMode(Animation.REVERSE);
以上代碼含義為從view的起點開始,保持y軸不變,沿著x平移200個像素,平移時間為2秒,重復執行一次,第二次執行方式與第一次執行方式完全相反,如下圖:
以上是java代碼實現的方式,亦可以使用xml實現,如下:
/res/anim/translate.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="0" android:toXDelta="200" android:fromYDelta="0" android:toYDelta="0" android:duration="2000" android:repeatCount="1" android:repeatMode="reverse" android:interpolator="@android:anim/accelerate_decelerate_interpolator"/> </set>
fromXDelta:View x軸起點
toXDelta:View x軸終點
fromYDelta:View y軸起點
toYDelta:View y軸終點
duration:動畫持續時間
repeatCount:動畫執行次數
repeatMode:動畫執行模式
interpolator:插值器,可以理解為View動畫值的改變規律
java中調用:
private Animation mTranslateAnimation; mTranslateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate); mTranslateIv.startAnimation(mTranslateAnimation);
使用Java或者xml實現動畫並無什麼不同,采用哪種完全取決於自己的編程習慣,但如果單純從擴展性來說,顯然xml方式更占優。
AlphaAnimation使用方法如下:
private AlphaAnimation mAlphaAnimation; //不透明度從100%到0 mAlphaAnimation = new AlphaAnimation(1, 0); mAlphaAnimation.setDuration(2000); mAlphaAnimation.setRepeatCount(1); mAlphaAnimation.setRepeatMode(Animation.REVERSE);
以上代碼含義是在2秒內將View的不透名度從1變為0,總共執行2次,第一次和第二次執行動畫過程相反,效果如下圖:
xml實現方法可參照TranslateAnimation
ScaleAnimation使用方法如下:
mScaleAnimation = new ScaleAnimation(1, 2, 1, 2); mScaleAnimation.setDuration(2000); mScaleAnimation.setRepeatCount(1); mScaleAnimation.setRepeatMode(Animation.REVERSE);
上面ScaleAnimation構造函數中四個參數分別是:
fromX:起始x方向大小
toX:最終x方向大小
fromY:起始y坐標
toY:最終y坐標
上面代碼含義為將View在2秒內橫豎方向增大一倍,第二次是在原來的基礎上縮小一倍,效果圖如下:
xml實現方法同參照TranslateAnimation
RotateAnimation使用方法如下:
mRotateAnimation = new RotateAnimation(0, 360); mRotateAnimation.setDuration(2000); mRotateAnimation.setRepeatCount(1); mRotateAnimation.setRepeatMode(Animation.REVERSE);
上面代碼含義為在2秒內將View旋轉360度,再旋轉回來,效果如下:
二、Frame Animation
看過電影的人也許知道,電影是由一張一張圖片組成的,只不過圖片切換速度快,在人視覺中看到的是連續效果。Frame Animation亦同樣基於此原理實現,事先准備幾張圖片,按特定的順序排好,然後使用特定的動畫類將其播放,基於這種動畫實現方式,Frame Anmation亦有一個中文名:逐幀動畫。
實現這種動畫需要使用到AnimationDrawable類,它繼承於Drawable,使用方式如下:
private AnimationDrawable mAnimationDrawable; mAnimationDrawable = new AnimationDrawable(); //增加圖片,並設定圖片播放時間 mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.australia), 500); mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.austria), 500); mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.china), 500); mAnimationDrawable.start();
上面代碼是將三張圖片按照指定的順序,指定的時間播放,以達到動畫效果,如下圖:
同樣亦可以使用xml方式實現,代碼如下:
/anim/frame.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/australia" android:duration="500"/> <item android:drawable="@drawable/austria" android:duration="500"/> <item android:drawable="@drawable/china" android:duration="500"/> </animation-list>
xml中調用:
<ImageView android:id="@+id/frame_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@anim/frame"/>
java中調用:
private ImageView mFrameIv; private AnimationDrawable mAnimationDrawable; mFrameIv = (ImageView) findViewById(R.id.frame_iv); mAnimationDrawable = (AnimationDrawable) mFrameIv.getBackground(); mAnimationDrawable.start();
關於Frame Tween的知識比較簡單,熟悉AnimationDrawable便行,下面介紹本章最重要的Property Animation。
三、Property Animation
中文亦叫屬性動畫,如其名字一樣,可以改變對象的屬性,注意是對象,不是View,而且是任意對象,只要對象符合一定條件即可,上述中的Tween Animation僅僅只能操作View,對於View之外的對象則無能為力,並且其未改變View的屬性,僅僅是通過父類View對其重繪達到動畫效果;而Frame Animation動畫功能則過於簡單。隨著我們Android應用的發展,能發現Tween Animation、Frame Animation有時候並不能達到理想的效果,谷歌亦意識到了這點,故而在Android3.0之後增加了強大的屬性動畫。
Property Animation有兩個類可供使用:ValueAnimator、ObjectAnimator。這兩個類均直接或間接繼承於Animator
ObjectAnimator使用方式如下:
private ObjectAnimator mObjectAnimator; //設置不透明度從1到0變化 mObjectAnimator = ObjectAnimator .ofFloat(mObjectAnimatorIv, "alpha", 1, 0) .setDuration(1000); //設置插值器,先加速後減速 mObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); //動畫重復執行一次 mObjectAnimator.setRepeatCount(1); //設置執行模式 mObjectAnimator.setRepeatMode(ValueAnimator.REVERSE); mObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //獲取當前的動畫值 float cVal = (Float) animation.getAnimatedValue(); //根據動畫值縮放當前View mObjectAnimatorIv.setScaleX(cVal); mObjectAnimatorIv.setScaleY(cVal); } });
上面代碼意思是將當前View不透明度從1按照一定規律變為0,第一句代碼中的ofFloat(mObjectAnimatorIv, "alpha", 1, 0)中的alpha代表不透明度,有人可能會說我可以寫其他的嗎?當然可以,比如寫成ofFloat(mObjectAnimatorIv, "tmg", 1, 0),但你會發現動畫執行後不會有效果,因為寫這個字符串的前提是當前View或者當前View的父類中實現了這個字符串的get、set方法,即getAlpha、setAlpha,當動畫執行時,動畫類會通過調用setAlpha來改變View的alpha屬性,達到想要的動畫效果。那這個alpha是怎麼從1便到0的呢?Property Animation中有一個TypeEvaluator,這個屬性的含義是根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值,上例中的alpha便是這樣從1變到0的,但是上面並沒設置TypeEvaluator啊?其原因是Property Animation
會配置一個默認的TypeEvaluator,如果一定要顯性設置,有幾個寫好的TypeEvaluator供選擇:
IntEvaluator:屬性值的類型為int
FloatEvaluator:屬性值的類型為float
ArgbEvaluator:屬性的值類型為十六進制顏色值
如果上述沒有你需要的TypeEvaluator,你亦可以選擇繼承TypeEvaluator自定義一個類似的TypeEvaluator
從上面代碼中我們還可以看到:
float cVal = (Float) animation.getAnimatedValue(); mObjectAnimatorIv.setScaleX(cVal); mObjectAnimatorIv.setScaleY(cVal);
其中animation.getAnimatedValue();是計算View當前屬性值,當然根據前面的設置,這個屬性值實在1到0之間變化,下面的兩行代碼是通過每個時刻不同的屬性值對View進行縮放,達到在改變透明度的同時,
又改變View大小的效果,效果圖如下:
同樣的,Property Animation也可以通過xml實現,類似上面兩種,不再介紹,讀者可從之後分享的源碼中看到
ValueAnimator的使用方式和ObjectAnimator很相似,唯一的區別是ValueAnimator不能直接設置屬性,即類似
mObjectAnimator = ObjectAnimator .ofFloat(mObjectAnimatorIv, "alpha", 1, 0) .setDuration(1000);
它只能這樣:
mValueAnimator = ValueAnimator.ofFloat(1, 0); mValueAnimator.setTarget(mValueAnimatorIv);
動畫效果可在監聽事件中實現,如:
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float animatedValue = (float) animation.getAnimatedValue(); mValueAnimatorIv.setAlpha(animatedValue); mValueAnimatorIv.setScaleX(animatedValue); mValueAnimatorIv.setScaleY(animatedValue); } });
談談Keyframe,keyframe是一個時間/值對,通過它可以定義一個在特定時間的特定狀態,
即關鍵幀,而且在兩個keyframe之間可以定義不同的Interpolator,就好像多個動畫的拼接,第一個動畫的結束點是第二個動畫的開始。keyframe是抽象類,要通過ofInt(),ofFloat()等獲得適當的keyframe,然後通過PropertyValuesHolder.ofKeyframe
獲得PropertyValuesHolder對象,如下例子:
Keyframe kf0 = Keyframe.ofInt(0, 400); Keyframe kf1 = Keyframe.ofInt(0.25f, 200); Keyframe kf2 = Keyframe.ofInt(0.5f, 400); Keyframe kf3 = Keyframe.ofInt(0.75f, 100); Keyframe kf4 = Keyframe.ofInt(1f, 500); PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf3, kf4); mKeyframesObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(mKeyframesObjectAnimationBtn, propertyValuesHolder); mKeyframesObjectAnimator.setDuration(2000); mKeyframesObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { android.util.Log.d("update", (animation.getAnimatedValue()).toString()); } });
動畫效果同樣是在onAnimationUpdate中添加,上面僅僅是打個log
如果你想應用多個動畫,AnimationSet可以幫到你,AnimationSet提供了一個把多個動畫組合成一個組合的機制,並可設置組中動畫的時序關系,如同時播放,順序播放等。
如下代碼:
mAnimatorSet = new AnimatorSet(); mAnimatorSet.play(mObjectAnimator).before(mValueAnimator); mAnimatorSet.play(mValueAnimator).before(mKeyframesObjectAnimator);
play是播放,before是在當前動畫之前播放,還有2個方法with、after,分別是與當前動畫同時播放,在當前動畫之後播放,效果如下:
上面是三個動畫按照一定順序播放,有時候我們需要比較復雜的動畫效果時,這個類會很重要。
四、擴展介紹
interpolator:插值器,代表動畫值的變化速度
repeatCount:動畫重復執行的次數
repeatMode:動畫執行模式,每次動畫執行方式是一樣還是按照相反方向執行
duration:動畫執行時間
evaluator:根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值
參考文章:
http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html
http://blog.csdn.net/lmj623565791/article/details/38092093
源碼:
https://github.com/taothreeyears/animation
Android自定義控件:進度條的四種實現方式 最近一直在學習自定義控件,搜了許多大牛們Blog裡分享的小教程,也上GitHub找了一些類似的控件進行學習。發現讀起來
Android Material Design:NavigationView抽屜導航菜單,materialdesign 需要添加的包: 測試
Android 視頻播放器 VideoView 的使用,播放本地視頻 和 網絡 視頻,androidvideoview1、布局文件 <?xml version=1
Android RecyclerView 和 CardView簡單使用,recyclerview簡單用法Android 5.0之後Android新增加的兩個UI控件Rec