Android Canvas的save(),saveLayer()和restore()淺談

來源:互聯網
上載者:User

標籤:android   style   blog   http   io   ar   color   os   使用   

save()  saveLayer()  restore()

1.在自訂控制項當中你onMeasure和onLayout的工作做完成以後就該繪製該控制項了,有時候需要自己在控制項上添加一些修飾來滿足需求

複寫onDraw(Canvas canvas),其中Canvas就像是一塊畫布,你自訂控制項的樣式就是在它上面完成的

Canvas ,Paint等基本概念就不贅述了。

2.下面就直接用demo來解釋標題列出的方法先介紹save()和

必須瞭解的相關知識:http://www.cnblogs.com/liangstudyhome/p/4126002.html

save() : 用來儲存Canvas的狀態,save()方法之後的代碼,可以調用Canvas的平移、放縮、旋轉、裁剪等操作!

restore():用來恢複Canvas之前儲存的狀態(可以想成是儲存座標軸的狀態),防止save()方法代碼之後對Canvas執行的操作,繼續對後續的繪製會產生影響,通過該方法可以避免連帶的影響

 

通過一個例子說明一下:

 

例如:我們想在畫布上繪製一個向右的三角箭頭,當然,我們可以直接繪製,另外,我們也可以先把畫布旋轉90°,畫一個向上的箭頭,然後再旋轉回來(這種旋轉操作對於畫圓周上的標記非常有用),最後,我們在右下角繪一個20像素的圓!

網上對這個問題的解決說是旋轉回來,我的感覺其實save()儲存的就是Canvas中座標軸的狀態。

MyView:

 

 1 public class MyView extends View { 2  3     public final static String TAG = "Example"; 4  5     private Paint mPaint = null; 6  7     public MyView(Context context) { 8         super(context); 9         mPaint = new Paint();10     }11 12     public MyView(Context context, AttributeSet attrs) {13         super(context, attrs);14     }15 16     public MyView(Context context, AttributeSet attrs, int defStyle) {17         super(context, attrs, defStyle);18     }19 20     @Override21     protected void onDraw(Canvas canvas) {22         super.onDraw(canvas);23         Paint background = new Paint();24         Paint line = new Paint();25         line.setStrokeWidth(4);26         background.setColor(Color.GRAY);27         line.setColor(Color.RED);28 29         int px = 500;30         int py = 500;31 32         canvas.drawRect(0, 0, px, py, background);33         canvas.save();34         canvas.rotate(90, px / 2, py / 2);35         // 畫一個向上的箭頭36         canvas.drawLine(px / 2, 0, 0, py / 2, line); // 左邊的斜杠37         canvas.drawLine(px / 2, 0, px, py / 2, line);// 右邊的斜杠38         canvas.drawLine(px / 2, 0, px / 2, py, line);// 垂直的豎杠39 40         canvas.restore();41         canvas.drawCircle(px - 100, py - 100, 50, line);42 43     }44 45 }

 

運行後的效果是:

 將canvas.save()和canvas.restore()這兩行代碼注釋掉以後啟動並執行效果是:

 

 

 

 為什麼有這種差異出現呢?

在 canvas.save()之前,Canvas的座標軸是:

save()之後就是把這種狀態的座標軸狀態儲存了下來,

canvas.rotate(90, px / 2, py / 2)圍著圓心旋轉之後,座標軸變成:


1 canvas.drawLine(px / 2, 0, 0, py / 2, line); // 左邊的斜杠2 canvas.drawLine(px / 2, 0, px, py / 2, line);// 右邊的斜杠3 canvas.drawLine(px / 2, 0, px / 2, py, line);// 垂直的豎杠

 


 這一些列畫圖操作時在變換後的座標軸上畫出來的,所以是一個往右方向的箭頭。

當調用canvas.restore()後座標軸恢複到canvas.save()之前的狀態。所以canvas.drawCircle(px - 100, py - 100, 50, line)參考的座標軸是cnavas.save()之前的座標軸。

這樣也就能說通為什麼不用Canvas.save()和用Canvas.save()圓圈位置為什麼不相同的原因了。


saveLayer

Canvas 在一般的情況下可以看作是一張畫布,所有的繪圖操作如drawBitmap, drawCircle都發生在這張畫布上,這張畫板還定義了一些屬性比如Matrix,顏色等等。但是如果需要實現一些相對複雜的繪圖操作,比如多層動畫,地圖(地圖可以有多個地圖層疊加而成,比如:政區層,道路層,興趣點層)。Canvas提供了圖層(Layer)支援,預設情況可以看作是只有一個圖層Layer。如果需要按層次來繪圖,Android的Canvas可以使用SaveLayerXXX, Restore 來建立一些中介層,對於這些Layer是按照“棧結構“來管理的:       


 建立一個新的Layer到“棧”中,可以使用saveLayer, savaLayerAlpha, 從“棧”中推出一個Layer,可以使用restore,restoreToCount。但Layer入棧時,後續的DrawXXX操作都發生在這個Layer上,而Layer退棧時,就會把本層繪製的映像“繪製”到上層或是Canvas上,在複製Layer到Canvas上時,可以指定Layer的透明度(Layer),這是在建立Layer時指定的:public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)本例Layers 介紹了圖層的基本用法:Canvas可以看做是由兩個圖層(Layer)構成的,為了更好的說明問題,我們將代碼稍微修改一下,預設圖層繪製一個紅色的圓,在新的圖層畫一個藍色的圓,新圖層的透明度為0×88。     

 

 1 public class Layers extends Activity { 2  3     @Override 4     protected void onCreate(Bundle savedInstanceState) { 5         super.onCreate(savedInstanceState); 6         setContentView(new SampleView(this)); 7     } 8  9     private static class SampleView extends View {10         private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG11                 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG12                 | Canvas.CLIP_TO_LAYER_SAVE_FLAG;13 14         private Paint mPaint;15 16         public SampleView(Context context) {17             super(context);18             setFocusable(true);19 20             mPaint = new Paint();21             mPaint.setAntiAlias(true);22         }23 24         @Override25         protected void onDraw(Canvas canvas) {26             canvas.drawColor(Color.WHITE);  27             canvas.translate(10, 10);  28             mPaint.setColor(Color.RED);  29             canvas.drawCircle(75, 75, 75, mPaint);  30             canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS);  31             mPaint.setColor(Color.BLUE);  32             canvas.drawCircle(125, 125, 75, mPaint);  33             canvas.restore(); 34          }35     }36 }

 

 分析:canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS)將一個layer推入棧中,後續的

1 mPaint.setColor(Color.BLUE);2 canvas.drawCircle(125, 125, 75, mPaint);

 

畫一個藍色圓是在這個layer中畫的,和之前畫紅色圓的不是同一個layer層。

在canvas.restore()被儲存的layer就在紅色圓layer上面了。

是:

demo下載

 

Android Canvas的save(),saveLayer()和restore()淺談

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.