編輯:關於Android編程
當我們看到別人的APP裡面或者寫的Demo裡面的一些很牛逼得動畫效果的時候,是否會有那麼一種沖動我要看看它的源代碼到底是怎麼寫的,為毛我就是寫不出這樣的動畫效果呢,為毛我只能做哪些簡單的平移,縮放,旋轉,透明度改變的動畫效果呢。呵呵,當你這麼想的時候,證明你應該存在兩種主要的問題:第一,就是你的確基礎知識不過關,別人用到的東西,你根本就沒有接觸過,但是這些東西的確是API裡面確實存在的東西。第二,就是你的經驗不夠,邏輯思維能力還有待提升。任何一個很酷很炫的動畫效果,都應該是由一系列的動畫效果合成的,這個時候就看你怎麼安排和處理每一個小的動畫效果最後合成你看到的動畫效果。下面先介紹Android中的幾種動畫,最後會對屬性動畫(Property Animation)做詳細的介紹:
補間動畫(Tween Animation):
所謂的補間動畫,個人理解其實就是定義了我們動畫的起始點和終止點的狀態,而動畫的過程我們是不關心的,只需要達到我們想要的效果就行。
a. 漸變動畫支持四種類型:平移(Translate)、旋轉(Rotate)、縮放(Scale)、不透明度(Alpha)。
b. 只是顯示的位置變動,View的實際位置未改變,表現為View移動到其他地方,點擊事件仍在原處才能響應。
c. 組合使用步驟較復雜。
d. View Animation 也是指此動畫。
幀動畫(Frame Animation):
所謂的幀動畫就是可以設置我們的動畫的每一幀的效果,其實視頻或者Gif的效果都是由許多張圖片在很短的時間內播放,從而產生動畫效果。
a. 用於生成連續的Gif效果圖。
b.DrawableAnimation也是指此動畫。
屬性動畫(Property Animation)
a. 支持對所有View能更新的屬性的動畫(需要屬性的setXxx()和getXxx())。
b. 更改的是View實際的屬性,所以不會影響其在動畫執行後所在位置的正常使用。
c. Android3.0 (API11)及以後出現的功能,3.0之前的版本可使用github第三方開源庫nineoldandroids.jar進行支持。
屬性動畫的相關的API:
ValueAnimator :值動畫執行類,常配合AnimatorUpdateListener使用。
ObjectAnimator :對象動畫執行類。
PropertyValuesHolder: 屬性存儲器,為兩個執行類提供更新多個屬性的功能。
AnimatorListener :動畫執行監聽,在動畫開始、重復、結束、取消時進行回調。
Keyframe :為PropertyValuesHolder提供多個關鍵幀的操作值。
AnimatorSet :一組動畫的執行集合類:設置執行的先後順序,時間等。
TimeInterpolator :時間插值,用於控制動畫執行過程。
AnimatorUpdateListener:動畫更新監聽。
TypeEvaluator :類型估值,用於設置復雜的動畫操作屬性的值。
ValueAnimator和ObjectAnimator是屬性動畫裡面經常使用的對象類,ObjectAnimator是ValueAnimator的子類,看看ValueAnimator的類結構:
在ValueAnimator類中經常用到的幾個方法:
public static ValueAnimator ofInt(int... values){ } //設置類型為int的屬性的值,例如X,Y坐標,可變長的數組值,設置屬性值在之間變化
public static ValueAnimator ofFloat(float... values) { } //設置類型為float的屬性的值,例如alpha,translationX,translationY等等屬性
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) //當我們對某一個控件的多個屬性實行動畫的時候 可以用PropertyValuesHolder保存每一個屬性的動畫效果,最後調用這個方法組合起來,參數也是一個可變長的。
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) //設置某個對象的動畫 在後面做詳細介紹
1.ObjectAnimator
下面先講講ObjectAnimator的用法(因為實際中這個用的更多。PS:完全個人感覺)
ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0f,200f); oa.setDuration(1000); oa.start();
上面代碼實現的是改變控件iv的translationX的值,從0到200,0f表示從0開始使X坐標平移,這個值可以自己設置,當我們是指的值加入設定為100f的時候,給我們的感覺就是控件iv首先跳到X坐標為100f處(這個100指的是相對於控件坐標的左上角為原點)
左圖為0f,200f時的效果,右圖為100f,200f的效果,明顯感覺右側的動畫突然跳躍了一段距離。
其他各種屬性的值,我們可以去對應控件的類或者頂級View的源碼裡面查看,不再一一贅述了。
ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0f,100f); oa.setDuration(2000); //設置重復次數 次數為-1的時候重復模式INFINITE才有作用意思是一直重復執行 oa.setRepeatCount(-1); //設置重復的模式 INFINITE 無限重復執行 RESTART 從開始重復執行 REVERSE 反轉重復執行(類似反著執行一次) oa.setRepeatMode(ObjectAnimator.REVERSE); //動畫在延遲1000毫秒之後開始 oa.setStartDelay(1000); //開始動畫 oa.start();
上面的動畫效果是重復執行,注釋很清楚了。
2.PropertyValueHolder
他可以設置多個動畫同時作用於同一個空間,有點類似於補間動畫的動畫集合AnimationSet
//屬性存儲器 PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 0,100,200,300); //縮放動畫,X Y軸縮放比例從原始比例,縮小到最小,再放大到原始比例1f 再又縮放到最小 最後放大到最大 PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f,0f,1f,0f,1f); PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f,0f,1f,0f,1f); //同時執行三個動畫 ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(iv,pvh1,pvh2,pvh3); oa.setDuration(1000); oa.start();
最後運行的動畫效果 可能由於浏覽器的原因,沒有縮放到最小,後面會將源碼留下,大家可以去模擬器上看看效果。
AnimatorSet可以實現同樣的類似於PropertyValueHolder的功能 但是AnimatorSet功能更強大,它可以設置某一個動畫在另外一個動畫前面或者後面執行,還可以設置某幾個動畫同時執行。
AnimatorSet set = new AnimatorSet(); //透明度 ObjectAnimator anim1 = ObjectAnimator.ofFloat(iv, "alpha", 0f,1f); anim1.setDuration(4000); //橫向平移 ObjectAnimator anim2 = ObjectAnimator.ofFloat(iv, "translationX", 0f,100f); anim2.setDuration(3000); //縱向平移 ObjectAnimator anim3 = ObjectAnimator.ofFloat(iv, "translationY", 0f,100f); anim3.setDuration(3000); //旋轉 ObjectAnimator anim4 = ObjectAnimator.ofFloat(iv, "rotation", 0f,360f); anim4.setDuration(500); //制定動畫執行的順序 //anim1 在 anim2 之前執行 set.play(anim1).before(anim2); //anim2 anim3 同時執行 set.play(anim2).with(anim3); //anim4 在 anim3之後執行 set.play(anim4).after(anim3); set.start();
執行效果如下圖
AnimatorSet裡面有幾個控制動畫執行先後順序的方法
after(Animator anim) 將現有動畫插入到傳入的動畫之後執行after(long delay) 將現有動畫延遲指定毫秒後執行before(Animator anim) 將現有動畫插入到傳入的動畫之前執行with(Animator anim) 將現有動畫和傳入的動畫同時執行
3.關鍵幀KeyFrame
意思就是設置動畫的某一幀(關鍵幀)的效果,先看代碼和效果圖,在根據代碼和效果圖仔細講解
//關鍵幀 //Keyframe 定義動畫在特定的時間點上特定的狀態 //第一個0,動畫的執行進度,第二個0,初始的狀態(0度) // Keyframe kf0 = Keyframe.ofFloat(0f,0f); //動畫執行到30%時,應該旋轉了360度 //Keyframe kf1 = Keyframe.ofFloat(0.2f,360f); // Keyframe kf1 = Keyframe.ofFloat(0.2f,1f); //動畫執行到100%,重新旋轉到0度 // Keyframe kf2 = Keyframe.ofFloat(1f,0f); Keyframe kf0=Keyframe.ofFloat(0f,0f); Keyframe kf1=Keyframe.ofFloat(0.1f,100f); Keyframe kf2=Keyframe.ofFloat(1f,300f); //區別:ObjectAnimator.ofFloat(iv, "rotation", 0f,360f,0f); //將關鍵幀打包 PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", kf0,kf1,kf2); // PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("alpha", kf0,kf1,kf2); //創建屬性動畫對象 ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(iv,holder); oa.setDuration(2000); oa.start();代碼的第10定義了關鍵幀kf0,調用了Keyframe.ofFloat(float fraction , float value) ,第一個參數代表的是動畫執行的進度,在此kf0的fraction=0f,就是動畫開始執行的時候,屬性類型為Float的值為value
4.事件監聽
ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "alpha", 1f,0f); oa.setDuration(1000); oa.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { //動畫開始時調用 } @Override public void onAnimationRepeat(Animator animation) { //動畫重復時調用 } @Override public void onAnimationEnd(Animator animation) { ////動畫結束時調用 //移除按鈕 ViewGroup parent = (ViewGroup) btn.getParent(); if (parent != null) { parent.removeView(btn); } } @Override public void onAnimationCancel(Animator animation) { //動畫取消時調用 } }); oa.start();代碼中為ObjectAnimator設置了事件監聽AnimatorListener,可以重寫其中的四個方法onAnimationStart表示動畫剛剛開始執行時候的回調,onAnimationRepeat動畫重復執行的時候回調,onAnimationEnd動畫執行完畢的時候的回調,大部分應用程序都會復寫這個方法來執行相關的操作,onAnimationCancel動畫取消的時候回調。
如果在程序中我們需要監聽動畫的完成或者執行狀態但是不想回調或者復寫AnimatorListener的方法的時候,可以用AnimatorListener的子類AnimatorListenerAdapter,選擇你需要重寫的方法,而不必重寫所有的方法。
oa.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(android.animation.Animator animation) { // TODO Auto-generated method stub super.onAnimationEnd(animation); } });
5.插值器Interpolator
對於不同的插值器有不同的動畫效果,可以調用ObjectAnimator的setInterpolator()方法設置自己向想要的插值器。TimeInterpolator時間插值器,是以上所有插值器的父接口,我們可以寫自己的插值器的實現,重寫其getInterpolation方法,也可以用上面圖片所提到的幾種插值器,這都是谷歌幫我們寫好的。
AccelerateInterpolator:加速差值,意思就是動畫執行的速度越來越快。
AniticipateInterpolator:動畫執行的效果是控件會從動畫開始執行的地方倒退一段距離之後再執行,和OvershootInterpolator相反,OvershootInterpolator是在動畫執行完成之後繼續執行一段距離,有點類似跳出當前控件所在的父容器之外的感覺
LinearInterpolator:線性插值器,就是類似勻速運動的效果
DecelerateInterpolator:減速插值器,開始動畫執行快,後面沒執行慢
BounceInterpolator:動畫執行的效果類似乒乓球掉在地上的效果,落地之後會反彈,知道最後完全停止。
CycleInterpolator:字面意思 ,循環插值器,可以使動畫循環執行多次,類似repeate效果,控制translationX屬性可以做出控件的抖動效果
當然還可以有這幾種插值器的組合效果。
6ValueAnimator
正如前面所說,ValueAnimator就是值動畫執行類,常配合AnimatorUpdateListener使用。他和ObjectAnimator的區別是,ObjectAnimator是ValueAnimator的子類,在調用ofFloat,ofInt....創建ValueAnimator的時候我們不需要也不能像ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationY", 0,300); 這樣為動畫指定相應的屬性(translationY),俗套的說,就是計算你知道你要改變的屬性輸translationY但是你也不能再創建的時候指定它,你只能指定屬性的取值范圍,例如ValueAnimator va = ValueAnimator.ofFloat(0f,200f); 你只知道0f~200f但是從代碼字面意思你不知道到底是什麼屬性0f~200f,這時候就需要配合AnimatorUpdateListener來使用了,在AnimatorUpdateListener的onAnimationUpdate中寫我們的動畫的具體執行邏輯。
ValueAnimator va = ValueAnimator.ofFloat(0f,200f); va.setDuration(2000); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float v = Float.parseFloat(animation.getAnimatedValue().toString()); //如果要使動畫同時適配API11以下的版本 就得使用開源jar包nineoldandroids.jar進行統一適配 //操作方法就變成了ViewHelper.setTranslationX(iv, v); iv.setTranslationX(v); //優點:可以同時在回掉方法中,更新多個控件的屬性 //使用ObjectAnimator還是ValueAnimator取決於是否在一個動畫中更新多個控件的屬性 //ViewHelper.setTranslationY(btn, v); } }); va.start();
例子很簡單,但是能夠說明ValueAnimator的簡單使用方法,我們可以在回調方法onAnimationUpdate方法中處理多個控件(其他非動畫執行的控件的狀態),當然ValueAnimator還可以配合AnimatorListener使用監聽動畫執行的開始,結束,重復,取消等操作,也可以使用AnimatorListenerAdapter只監聽其中的動畫執行的某一個狀態。
7 TypeEvaluator
類型估值,用於設置復雜的動畫操作屬性的值,它是一個接口,有3個實現類,分別為IntEvaluator,FloatEvaluator,ArgbEvaluator,從字面意思可以看出他們的意思。和上面的ofFloat,ofInt有異曲同工之妙。這三個實現類都實現了TypeEvaluator中的抽象方法public T evaluate(float fraction, T startValue, T endValue); 其中float fraction表示動畫執行的進度,T startValue泛型startValue表示動畫開始執行的位置或者狀態,endValue代表動畫執行結束的位置或者狀態 ,用泛型T表示 說明開發者可以根據自己的需要,定義自己的TypeEvalotor,例如Integer,Float,Point,PointF...等等。下面說說他們的簡單用法。
FloatEvaluator evaluator=new FloatEvaluator(); ValueAnimator valueAnimator = ValueAnimator.ofObject(evaluator,0,200); valueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float x=Float.parseFloat(animation.getAnimatedValue().toString()); iv.setX(x); } }); valueAnimator.setDuration(3000); valueAnimator.start();上面動畫的意思是使控件IV的X坐標從0-200改變,類似做直線運動,效果圖就免了,很簡單。
下面來說說TypeEvaluator的用法,先上代碼和效果。
final PointF point = new PointF(); TypeEvaluatortypeEvaluator = new TypeEvaluator () { // @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { //fraction 就相當於進度0->1 // point.x=(endValue.x-startValue.x)*fraction; // point.y=(endValue.y-startValue.y)*fraction; point.x=(endValue.x-startValue.x)*fraction; point.y=600+200*(float) Math.sin(point.x/65); return point; } }; ValueAnimator valueAnimator = ValueAnimator.ofObject(typeEvaluator, new PointF(0,600),new PointF((float)(260*Math.PI),600)); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //getAnimatedValue方法返回的值,由evaluate計算得到的 PointF point = (PointF) animation.getAnimatedValue(); // ViewHelper.setX(iv, point.x); // ViewHelper.setY(iv, point.y); iv.setX(point.x); iv.setY(point.y); } }); valueAnimator.setDuration(3000); valueAnimator.start();
上面的代碼使用TypeEvaluator實現了控件IV沿著我們設置的正弦曲線運動,正弦函數為y=600+200*sin(x/65);
代碼第1行首先定義一個點PointF 應為裡面的坐標為float類型,所以使用PointF
代碼第2-13行定義了一個TypeEvalutor並重寫了evaluate方法 泛型T代表PointF
代碼第9行定義了點的x坐標為point.x=(endValue.x-startValue.x)*fraction;
代碼第10行定義了y坐標,我們根據正弦函數的函數方程式寫出point.y=600+200*(float) Math.sin(point.x/65); 由於手機屏幕的坐標的水平向右為X正方形,垂直向下為Y軸正方形,數字600 ,200 ,主要是為了增加Y軸的幅度,使動畫效果更加明顯,65主要是為了擴大X軸方向的距離。
代碼第14行創建ValueAnimator對象並調用ofObject方法,將TypeEvaluator,startValue,endValue傳遞給它。
代碼15行,添加動畫監聽,這正應證了前面說的ValueAnimator通常和ValueAnimator.AnimatorUpdateListener配對使用,在他的回調方法onAnimationUpdate裡面控制空間IV的x和y坐標 最後啟動動畫就得到上面的效果。
文章可能寫的不太全面,好多該詳細講解的地方,可能沒有講解到,本文只是講解了屬性動畫中常用的一些API,想要寫出非常炫酷的動畫效果,還是需要開篇所說的邏輯思維能力。希望本文能給大家帶來些幫助,謝謝。
Fragment 的出現一方面是為了緩解 Activity 任務過重的問題,另一方面是為了處理在不同屏幕上 UI 組件的布局問題,而且它還提供了一些新的特性(例如 Ret
一、禁用一對一的視頻1.1含有video:true的共有11項,分布在三個文件中,RTCMultiConnection.js(5個),Scalable-Broadcast
1.把eclipse工程配置文件復制到Android源碼根目錄下cp development/ide/eclipse/.classpath ./2.修改eclipse程序
msm8909+android5.1.1--打開調試(debug)串口1.共同修改的地方(1)kernel\arch\arm\configs\msm8909-1gb-CB