編輯:關於Android編程
在前面的文章中我們講述了Android動畫之視圖動畫學習了怎麼對一個view實現動畫,可以實現動畫包括平移,旋轉,縮放,漸變和幀動畫,這一篇我們來學習一個新的動畫實現方式。
Android在3.0引入了屬性動畫,既然之前已經有屬性動畫了,為什麼還要引入屬性動畫吶?視圖動畫不好用嗎?還是視圖動畫不能夠實現功能?隨著系統的迭代更新,和設計的發展,以前做app都是比較簡單的,但是現在的app越來越復雜,功能越來越多,動畫效果也更加的復雜,更阿基要求實時性和界面的絢麗,因此老的系統很多實現都已經改變,對新的功能也力不從心,所以才引入屬性動畫來改善動畫的效果, 主要有如下原因:
1,視圖動畫是非交互動畫,僅僅只是改變了顯示位置
2,視圖動畫種類有限,復雜的效果力不從心
3,視圖動畫調用onDraw來重繪界面,耗費資源
4,視圖動畫只能針對view實現動畫,對非view不能實現
我們分別解釋一下上面的四點:
視圖動畫是非交互動畫,僅僅只是改變了顯示位置
我們在上一章講述了視圖動畫是非交互動畫,這個雖然不是一個很大的缺陷,但是在真的需要交互的時候就力不從心了,要實現額外的代碼才能實現其效果,
視圖動畫種類有限,復雜的效果力不從心
其次在現階段很多app都有非常復雜的效果,僅僅依靠視圖動畫的組合往往很難實現,就算實現了效果,代碼也非常的多,可能難以維護。
視圖動畫調用onDraw來重繪界面,耗費資源
onDraw來返回重繪界面,這樣就導致耗費資源和性能,流暢性是一個app非常重要的體驗,雖然單一一個動畫不能特別明顯的拖慢性能,但是各個地方差值綜合就會導致體驗很差
視圖動畫只能針對view實現動畫,對非view不能實現
視圖動畫的種類僅僅只有四種,並且只能針對view實現,如果只是針對一個view的背景顏色,或者其他的屬性來實現動畫,就不能實現。
我們在上面大書特書了視圖動畫的不足,那是不是屬性動畫就完全彌補了視圖動畫的不足?答案是的:
1,屬性動畫真正改變的是對象的屬性
2,屬性動畫是可以交互的
3,屬性動畫針對view與非view都能實現動畫
4,如果屬性不存在,還可以自定義屬性來實現動畫
雖然屬性動畫有這樣那樣的優點,是不是視圖動畫我們就拋諸腦後,不在使用?是,也不是?如果你新開發一個app,並且不是支持3.0一下的版本,那最好是直接使用屬性動畫,那什麼時候使用視圖動畫?
1,現有代碼已經實現效果
2,視圖動畫能實現所需要的效果
3,視圖動畫只需要更少的代碼來實現
這裡我們主要注意一下視圖動畫與屬性動畫的異同。代碼結構很類似,但是根節點是不一樣的,視圖動是Animation,屬性動畫是Animator,視圖動畫有四個子類,平移,旋轉,縮放,漸變,這裡完全用ObjectAnimator來代替了。
在res/animator下定義動畫文件(ValueAnimator-animator,ObjectAnimator
–objectAnimator, AnimatorSet-set ) 代碼中采用AnimatorInflater().
loadAnimator()加載
采用ObjectAnimator或者ValueAnimator實現
我們上面講述了兩種動畫的實現方式。這裡我們先講述一下代碼實現,我們先來看看在視圖動畫的一個截圖,當時實現了平移,旋轉,縮放,漸變,那這裡我們用屬性動畫來實現一遍:
vcq9o6zO0sPHz8jAtL+0v7S/ydLUyrnTw7XEYXBp09DExNCpo788L3A+DQo8cD48aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20161004/20161004090051479.jpg" title="\" />
我們從圖片可以到,of類型的函數有很多種,有ofArgb,ofFloat,ofInt等,這裡有這麼多api,那我們使用哪一個?這裡我們主要使用ofFloat,因為這個函數是從3.0引入的,這個函數比較通用,其他的函數有的是4.0引入的,5.0引入的。因此這裡我們主要講解ofFloat:
ObjectAnimator.ofFloat(Object target, String propertyName, float... values)
各個屬性的解釋如下:
1,target作用的對象
2,propertyName作用的屬性,需要有public的setName函數
3,values可變參數,表示動畫執行的一組值
漸變
private void alpha() { ObjectAnimator alpha = ObjectAnimator.ofFloat(love, "alpha", 1.0f, 0.0f); alpha.setDuration(1000); alpha.start(); }
這裡使用的屬性是alpha,1.0f表示完全不透明,0.0f表示完全透明。
平移
private void translate() { ObjectAnimator translate = ObjectAnimator.ofFloat(love, "translationX", 200f); translate.setDuration(1000); translate.start(); }
這裡使用的是translationX屬性,只平移了x軸,Y軸不做變化。
縮放
private void scale() {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, “scaleX”, 1.0f, 2.0f);
scaleX.setDuration(1000);
scaleX.start();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, “scaleY”, 1.0f, 2.0f);
scaleY.setDuration(1000);
scaleY.start();
}
這裡使用了scaleX與scaleY屬性,1.0f表示原始大小,2.0f表示放大一倍。默認縮放為中心縮放。
旋轉
private void rotate() { ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, 360f); rotate.setDuration(1000); rotate.start(); }
這裡使用的是rotation屬性,旋轉了360度,默認的旋轉中心為視圖中心。
上面我使用了一系列屬性,我怎麼知道哪些屬性可以用哪些屬性不能用。這裡我們去查找對應view所包含的屬性就知道了。
上面我們都是使用已知的屬性,如果一個view我們想要實現的效果沒有對應的屬性怎麼辦?
直接添加set函數
包裝原有類,添加set函數
采用ValueAnimator實現
這裡我們解釋以下上面的情況,第一種如果你有權限,或者是自定義的view,如果沒有對應屬性,我們可以手動添加對應的屬性,第二種情況,我們可以包裝現有類,添加對應的屬性,第三種我們可以采用ValueAnimator來實現,這裡我們來包裝一下原有類,後面我們會講解ValueAnimator的實現。
我們就以上述縮放效果來演示,上面我們使用了兩個屬性scaleX,scaleY來縮放一個view,這裡我們用一個屬性scale屬性來縮放,但是ImageView沒有縮放這個屬性,那怎麼辦?
public class WrapperView { public ImageView target; private float scale; public WrapperView(ImageView target) { this.target = target; } public float getScale() { return scale; } public void setScale(float scale) { this.scale = scale; target.setScaleX(scale); target.setScaleY(scale); } }
我們包裝對應的imageview,給他添加對應的scale屬性,之後在代碼中使用。動畫代碼如下:
private void addProperty() { WrapperView view = new WrapperView(love); ObjectAnimator scale = ObjectAnimator.ofFloat(view, "scale", 1.0f, 2.0f); scale.setDuration(1000); scale.start(); }
這裡我們使用的屬性就是上述添加的scale屬性。這樣我們就實現了縮放的效果。
我們在視圖動畫時講過,動畫有並行,串行,屬性動畫也有這些組合。那我們接下來就講述一下這些效果。
並行動畫,就是說多個動畫同時執行,比如我們在旋轉的同時縮放一個view,這裡主要有三種方式實現:
1:多個ObjectAnimator實現
private void togetherAnim1() { ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, 360f).setDuration(1000); ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000); ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000); // rotate.start(); // scaleX.start(); // scaleY.start(); AnimatorSet set = new AnimatorSet(); set.playTogether(rotate, scaleX, scaleY); set.setDuration(1000); set.start(); }
這裡我們定義了三個ObjectAnimator,之後用AnimatiorSet來進行執行。調用playTogether來同時執行這個三個動畫,還有一種方式是,可以分別start三個動畫也能實現效果。
這裡有人可能會有疑問,連續三個start那不應該是串行的嗎?怎麼會是並行的吶?其實這裡的start,動畫並沒有立即開始執行,而是等待下一個刷新時間戳過來才執行的。
2:一個ObjectAnimator實現
private void togetherAnim2() { PropertyValuesHolder rotate = PropertyValuesHolder.ofFloat("rotation", 0f, 360f); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 2.0f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 2.0f); ObjectAnimator together = ObjectAnimator.ofPropertyValuesHolder(love, rotate, scaleX, scaleY); together.setDuration(1000); together.start(); }
這裡我們使用PropertyValuesHolder來實現,定義三個PropertyValuesHolder,它與ObjectAnimator的區別是沒有target屬性,之後將PropertyValuesHolder放置到ObjectAnimator裡面,之後start ObjectAnimator動畫。
3:采用ViewPropertyAnimator實現
private void togetherAnim3() { love.animate().rotation(360f).scaleX(2.0f).scaleY(2.0f).setDuration(1000).start(); }
該方式系統已經實現了一個幫助方法,animate,之後可以鏈式的執行各個屬性。該方式代碼量是最少了的。
前面已經實現了並行,我們調用了playTogether,這裡我們只要換成另外一種方法就可以實現串行。
private void sequenceAnim() { ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, 360f).setDuration(1000); ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000); ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000); AnimatorSet set = new AnimatorSet(); set.playSequentially(rotate, scaleX, scaleY); set.setDuration(1000); set.start(); }
只需要將playTogether換成為playSequentially就可以了。
前面我們實現了並行與串行動畫,但是如果一個動畫既有串行又有並行怎麼辦?代碼如下:
private void compositeAnim() { ObjectAnimator translateY = ObjectAnimator.ofFloat(love, "translationY", -200f).setDuration(1000); ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000); ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000); ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, -45f).setDuration(1000); AnimatorSet set = new AnimatorSet(); set.play(scaleX).with(scaleY).with(rotate); set.play(translateY).after(scaleX); set.start(); }
這裡還是采用AnimatorSet來實現,with表示同時執行動畫。before方法,before裡面的代碼後執行,after方法,after裡面的動畫先執行。
前面我們已經講解了ObjectAnimator,我們前面的代碼結構中還有ValueAnimator,那ValueAnimator是什麼吶?
1,ValueAnimator是一個數值發生器
2,ValueAnimator不作用於任何屬性
3,需要在onAnimationUpdate獲取當前時間點發生的值
我們解釋一下上面的要點,首先ValueAnimator是一個數值發生器,就是他只產生數值,不對任何屬性起作用,因此他與ObjectAnimator不同,他不能產生動畫,動畫需要我們手動來處理。處理的方式就是在onAnimationUpdate中獲取產生的值。
那我們就來用ValueAnimator來實現一個動畫,我們實現一個倒計時的動畫:
private void countDown() { ValueAnimator countDown = ValueAnimator.ofInt(10, 0); countDown.setDuration(10000); countDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { textView.setText("" + animation.getAnimatedValue()); } }); countDown.start(); }
這裡我們用的ofInt函數,因為倒計時是整數,所以這裡用ofInt,我們在對動畫設置執行時長,最後在回調中獲取產生的值,animation.getAnimatedValue()就是當前產生的值。我們使用這個產生的值,實現倒計時動畫效果。
我們已經學習了怎麼用ObjectAnimator和ValueAnimator來處理動畫,但是如果需要監聽動畫的開始和結束又怎麼辦?
我們可以添加監聽:
private void alpha() { ObjectAnimator alpha = ObjectAnimator.ofFloat(love, "alpha", 1.0f, 0.0f); alpha.setDuration(1000); alpha.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Toast.makeText(ObjectAnimationActivity.this, "start", Toast.LENGTH_LONG).show(); ; } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); alpha.start(); }
我們可以對動畫添加Animator.AnimatorListener監聽,有四個回調函數,這樣我們就可以在動畫開始,結束進行處理。
不過上訴有四個回調,我們往往是不需要處理這麼多回調,僅僅只是想處理需要關注的回調,這種情況有解嗎?我們可以采用如下的方式進行處理:
private void translate() { ObjectAnimator translate = ObjectAnimator.ofFloat(love, "translationX", 200f); translate.setDuration(1000); translate.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); //TODO } }); translate.start(); }
對動畫設置AnimatorListenerAdapter,這裡我們只需要關注需要關注的回調。
還有一種監聽方式我們前面已經使用過了。就是ValueAnimator中添加監聽,我們可以添加ValueAnimator.AnimatorUpdateListener監聽,在onAnimationUpdate回調中進行處理。
在視圖動畫中,我們已經講解過插值器,這裡的插值器與視圖動畫中的插值器沒有什麼區別。因此就不在進行講述了。
這裡我們已經講述完成了屬性動畫的實現,還有其他的屬性沒有實現,在接下來的一篇中我們繼續講述剩下的屬性。
Application Fundamentals——應用程序基礎知識Key classes——關鍵類Activ
上一篇博文我們介紹了利用ViewPager和Fragment實現頂部滑塊左右滑動效果,具體參考(http://blog.csdn.net/a123demi/article
簡介通過android studio生成so庫的實踐。上一篇記錄的是通過eclipse生成so的方法eclipse生成so庫實踐,這裡記錄一下通過android stud
一丶本地音樂加載相當於就是listVIew應用扣丁音樂1.0前部分(gif圖大小限制)演示: 實體類Mp3Info(歌曲相關數據及get和set方法) 
Working with System PermissionsTo pr