android圖形系統詳解六:View layer

上一篇:/kf/201204/127348.html

View layers
  在所有版本的Android中,views都有畫到離屏緩沖的能力,這包括使用view的繪制cache,或使用Canvas.saveLayer().離屏緩沖,或者說層,有很多用處.你可以使用它們來為復雜的view動畫或使用組合效果時提高性能.例如,你可以使用Canvas.saveLayer()實現淡出效果,這個方法會臨時的把一個view畫到一個layer中然後使用一個透明系數把它組合回屏幕上.

  從Android3.0 (API level11)開始,你對何時以及如何通過View.setLayerType()方法來使用layer有瞭更多的控制能力.此方法有兩個參數:你想使用的layer的類型和一個可選的Paint對象,這個對象描述瞭layer應被如何組合.你可以使用Paint參數來應用顏色過濾,或指定混合模式或不透明度到一個layer.view可以使用以下三個類型之一:
• LAYER_TYPE_NONE:view按一般方式繪制,不使用離屏緩沖.這是默認的行為.
• LAYER_TYPE_HARDWARE:如果應用被硬加速瞭,view會被繪制到一個硬件紋理中.如果應用沒被硬加速,此類型的layer的行為同於LAYER_TYPE_SOFTWARE.
• LAYER_TYPE_SOFTWARE:view被繪制到一個bitmap中.

  要使用哪種layer類型取決於你的目標:
• 性能:使用一個硬件layer類型把view畫到硬件紋理中.當一個view被畫到一個layer中,它的繪制代碼直到調用invalidate()時才會被執行.一些動畫,比如透明變化的動畫,可以直接在layer上應用,這對GPU來說輕而易舉.
• 視覺效果:使用硬件或軟件layer類型和一個Paint將視覺特效應用到view上.比如,你可以在後臺用ColorMatrixColorFilter以黑白色畫一個view.
• 兼容性:使用一個軟件layer類型來強制view以軟件方式繪制.如果一個view是硬加速的(比如,如果你的整個應用是硬加速的),但呈現時出現問題,改用軟件方式繪制是一個避開硬件呈現管道限制的最簡單的方式.
View layers 和動畫
  當你的應用被硬加速時,硬件layer可以提供更快更平滑的動畫.當向一個有很多繪制操作的復雜的view應用動畫時,要永遠保證以60fps的速度運行是不可能的.但這可以通過使用硬件layers把view呈現到硬件紋理中來減輕一些負擔.硬件紋理之後可以被用來產生動畫,避免view為瞭產生動畫而不斷的重畫自己.view在其屬性發生改變而調用invalidate()或你主動調用invalidate()之前不會重畫,如果你正在你的應用運行動畫但是並不能獲得平滑的效果,那麼可以考慮在你的動畫view上啟用硬件layer.

  當一個view被硬件layer所支持,它的一些屬性的處理就跟layer混合到屏幕上的方式相關瞭.設置這些屬性的操作將變得更高效,因為它們不再導致view變得無效再重繪瞭.下面列出的就是這些屬性,調用這些屬性的設置器時會對invalidation操作產生最佳的優化並且不再重畫目標view:
• alpha:改變layer的透明度
• x, y,translationX, translationY:改變layer的位置
• scaleX,scaleY:改變layer的大小
• rotation,rotationX, rotationY: 在3D空間中改變layer的方向.
• pivotX,pivotY: 改變layer的變換原點坐標.
  這些屬性是在使用一個ObjectAnimator為view產生動畫時使用的.如果你想操作這些屬性,調用適當的setter或getter即可.例如,要改變透明屬性,調用setAlpha().下面的代碼片段演示瞭讓一個View繞Y軸進行三維變換的最佳方法:
[javascript]
1. view.setLayerType(View.LAYER_TYPE_HARDWARE, null); 
2. ObjectAnimator.ofFloat(view, "rotationY", 180).start(); 
 
  因為硬件layers使用顯卡內存,所以強烈建議你隻在動畫期間使用它們並在動畫結束後禁止它們.你可以使用動畫偵聽器來做到:
[javascript]
1. View.setLayerType(View.LAYER_TYPE_HARDWARE, null); 
2. ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); 
3. animator.addListener(new AnimatorListenerAdapter() { 
4.     @Override 
5.     public void onAnimationEnd(Animator animation) { 
6.         view.setLayerType(View.LAYER_TYPE_NONE, null); 
7.     } 
8. }); 
9. animator.start(); 
 
提示和技巧
  切換到2D圖形硬加速能立即提升性能,但是你仍然需要按照以下建議來有效使用GPU:
• 減少你應用中views的數量
  系統畫的views越多,就越慢.這對軟件呈現管線來說也是一樣.減少views是優化你的UI的最簡單的辦法.
• 避免過度繪制
  不要在彼此的上面畫太多layers.移除那些完全被別的不透明view遮蓋的view們.如果你需要把多個layer混合畫到每個view的上面,應考慮把它們合並到一個layer中.對於當前硬件的一個好原則是畫的次數不要超過每幀屏幕上像素的2.5倍(透明像素按位圖計數).
• 不要在繪制方法們中創建render對象
  一個常見的錯誤就是在每次調用繪制方法時都創建新的Paint或Path.這強制垃圾收集器運行得更頻繁,並且導致高速緩存和硬件管道優化不起作用.
• 不要太頻繁地修改shapes
  比如混合shapes,paths,和circles時,是使用紋理遮罩呈現的.每次你創建或修改一個path,硬件管道都創建一個新的遮罩,這個代價是很昂貴的.
• 不要太頻繁地修改bitmap
  你每次改變一個bitmap的內容,你下次去畫它時它會作為一個GPU紋理重新上載.
• 小心使用alpha(透明度)
  當你用setAlpha(),AlphaAnimation,或ObjectAnimator把一個view設為透明,它將被呈現到一個離屏緩沖中,此時就需要雙倍的填充速率.當在一個very大的view上應用透明度時,應考慮把view的layer類型設置為LAYER_TYPE_HARDWARE.

 

摘自 nkmnkm的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *