編輯:關於Android編程
在給大家講解了paint的幾個方法之後,我覺得有必要插一篇有關Canvas畫布的知識,在開始paint之前,我們講解了canvas繪圖的幾篇文章和cavas的save()、store()的知識,這篇是對Canvas的一個系統的補充,
protected void onDraw(Canvas canvas) { super.onDraw(canvas); } protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); }可以看到onDraw、dispatchDraw在傳入的參數中都有一個canvas對象。這個canvas對象是View中的Canvas對象,利用這個canvas對象繪圖,效果會直接反應在View中;
Canvas c = new Canvas(bitmap);或
Canvas c = new Canvas(); c.setBitmap(bitmap);其中bitmap可以從圖片加載,也可以創建,有下面幾種方法
//方法一:新建一個空白bitmap Bitmap bmp = Bitmap.createBitmap(width ,height Bitmap.Config.ARGB_8888); //方法二:從圖片中加載 Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.wave_bg,null);這兩個方法是最常用的,除了這兩個方法以外,還有其它幾個方法(比如構造一個具有matrix的圖像副本——前面示例中的倒影圖像),這裡就不再涉及了,大家可以去查看Bitmap的構造函數。
public class BitmapCanvasView extends View { private Bitmap mBmp; private Paint mPaint; private Canvas mBmpCanvas; public BitmapCanvasView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); mBmp = Bitmap.createBitmap(500 ,500 , Bitmap.Config.ARGB_8888); mBmpCanvas = new Canvas(mBmp); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(100); mBmpCanvas.drawText("啟艦大SB",0,100,mPaint); } }我們先看一下運行結果:
可以看到,毛線也沒有,這是為什麼呢?
我們仔細來看一下onDraw函數:
protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(100); mBmpCanvas.drawText("啟艦大SB",0,100,mPaint); }在onDraw函數中,我們只是將文字畫在了mBmpCanvas上,也就是我們新建mBmp圖片上!這個圖片跟我們view沒有任何關系好吧,我們需要把mBmp圖片畫到view上才行,所以我們在onDraw中需要加下面這句,將mBmp畫到view上
canvas.drawBitmap(mBmp,0,0,mPaint);所以改造後的代碼為:
public class BitmapCanvasView extends View { private Bitmap mBmp; private Paint mPaint; private Canvas mBmpCanvas; public BitmapCanvasView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); mBmp = Bitmap.createBitmap(500 ,500 , Bitmap.Config.ARGB_8888); mBmpCanvas = new Canvas(mBmp); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setTextSize(100); mBmpCanvas.drawText("啟艦大SB",0,100,mPaint); canvas.drawBitmap(mBmp,0,0,mPaint); } }這時候效果為:
/** * 保存指定矩形區域的canvas內容 */ public int saveLayer(RectF bounds, Paint paint, int saveFlags) public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)RectF bounds:要保存的區域的矩形。int saveFlags:取值有:ALL_SAVE_FLAG、MATRIX_SAVE_FLAG、CLIP_SAVE_FLAG、HAS_ALPHA_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG、CLIP_TO_LAYER_SAVE_FLAG總共有這六個,其中ALL_SAVE_FLAG表示保存全部內容,這些標識的具體意義我們後面會具體講;第二個構造函數實際與第一個是一樣的,只不過是根據四個點來構造一個矩形。
public class XfermodeView extends View { private int width = 400; private int height = 400; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public XfermodeView(Context context, AttributeSet attrs) { super(context, attrs); setLayerType(View.LAYER_TYPE_SOFTWARE, null); srcBmp = makeSrc(width, height); dstBmp = makeDst(width, height); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN); int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG); canvas.drawBitmap(dstBmp, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(layerID); } // create a bitmap with a circle, used for the "dst" image static Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } // create a bitmap with a rect, used for the "src" image static Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0, w, h, p); return bm; } }這段代碼大家應該很熟悉,這是我們在講解setXfermode()時的示例代碼,但在saveLayer前把整個屏幕畫成了綠色,效果圖如下:
那麼問題來了,如果我們把saveLayer給去掉,看看會怎樣:
protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN); canvas.drawBitmap(dstBmp, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint); mPaint.setXfermode(null); }效果圖就變這樣了:
我擦類……去掉saveLayer()居然效果都不一樣了……
我們先回顧下Mode.SRC_IN的效果:在處理源圖像時,以顯示源圖像為主,在相交時利用目標圖像的透明度來改變源圖像的透明度和飽和度。當目標圖像透明度為0時,源圖像就完全不顯示。
再回過來看結果,第一個結果是對的,因為不與圓相交以外的區域透明度都是0,而第二個圖像怎麼就變成了這屌樣,源圖像全部都顯示出來了。
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG); canvas.drawBitmap(dstBmp, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);我們講過,在畫源圖像時,會把之前畫布上所有的內容都做為目標圖像,而在saveLayer新生成的bitmap上,只有dstBmp對應的圓形,所以除了與圓形相交之外的位置都是空像素。
savelayer新建的畫布上的圖像做為目標圖像,矩形所在的透明圖層與之相交,計算結果畫在新建的透明畫布上。最終將計算結果直接蓋在原始畫布上,形成最終的顯示效果。
protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN); canvas.drawBitmap(dstBmp, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint); mPaint.setXfermode(null); }由於我們先把整個畫布給染成了綠色,然後再畫上了一個圓形,所以在應用xfermode來畫源圖像的時候,目標圖像當前Bitmap上的所有圖像了,也就是整個綠色的屏幕和一個圓形了。所以這時候源圖像的相交區域是沒有透明像素的,透明度全是100%,這也就不難解釋結果是這樣的原因了。
由於沒有調用saveLayer,所以圓形是直接畫在原始畫布上的,而當矩形與其相交時,就是直接與原始畫布上的所有圖像做計算的。
所以有關saveLayer的結論來了:
saveLayer會創建一個全新透明的bitmap,大小與指定保存的區域一致,其後的繪圖操作都放在這個bitmap上進行。在繪制結束後,會直接蓋在上一層的Bitmap上顯示。
public int saveLayer(RectF bounds, Paint paint, int saveFlags) public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)我們前面提到了saveLayer會新建一個畫布(bitmap),後續的所有操作都是在這個畫布上進行的。下面我們來分別看下saveLayer使用中的注意事項
public class SaveLayerUseExample_3_1 extends View{ private Paint mPaint; private Bitmap mBitmap; public SaveLayerUseExample_3_1(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.dog);; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mBitmap,0,0,mPaint); int layerID = canvas.saveLayer(0,0,getWidth(),getHeight(),mPaint,Canvas.ALL_SAVE_FLAG); canvas.skew(1.732f,0); canvas.drawRect(0,0,150,160,mPaint); canvas.restoreToCount(layerID); } }效果圖如下:
在onDraw中,我們先在view的原始畫布上畫上了小狗的圖像,然後利用saveLayer新建了一個圖層,然後利用canvas.skew將新建的圖層水平斜切45度。所以之後畫的矩形(0,0,150,160)就是斜切的。
而正是由於在新建畫布後的各種操作都是針對新建畫布來操作的,不會對以前的畫布產生影響,從效果圖中也明顯可以看出,將畫布水平斜切45度也只影響了saveLayer的新建畫布,並沒有對之前的原始畫布產生影響。
public class SaveLayerUseExample_3_1 extends View { private Paint mPaint; private Bitmap mBitmap; public SaveLayerUseExample_3_1(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog); ; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mBitmap, 0, 0, mPaint); int layerID = canvas.saveLayer(0, 0, 100, 100, mPaint, Canvas.ALL_SAVE_FLAG); canvas.drawRect(0, 0, 500, 600, mPaint); canvas.restoreToCount(layerID); } }
效果圖如下:
public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) public int saveLayerAlpha(float left, float top, float right, float bottom,int alpha, int saveFlags)相比saveLayer,多一個alpha參數,用以指定新建畫布透明度,取值范圍為0-255,可以用16進制的oxAA表示;
public class SaveLayerAlphaView extends View { private Paint mPaint; public SaveLayerAlphaView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setColor(Color.RED); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(100,100,300,300,mPaint); int layerID = canvas.saveLayerAlpha(0,0,600,600,0x88,Canvas.ALL_SAVE_FLAG); mPaint.setColor(Color.GREEN); canvas.drawRect(200,200,400,400,mPaint); canvas.restoreToCount(layerID); } }效果圖如下:
在saveLayerAlpha以後,我們畫了一個綠色的矩形,由於把saveLayerAlpha新建的矩形的透明度是0x88(136)大概是50%透明度,從效果圖中也可以看出在新建圖像與上一畫布合成後,是具有透明度的。
好了,這篇文章就先到這裡,下一篇詳細給大家講解有關參數中各個Flag的意義。
概述http Cache指的是web浏覽器所具有的復用本地已緩存的文檔”副本”的能力。我們知道,通過網絡獲取內容有時候成本很高,因而緩
三種得到LinearInflater的方法a. LayoutInflater inflater = getLayoutInflater();b. LayoutInflat
廢話不多說,先上效果圖在下載的時候藍色的邊會跟著下載的進度以前變化--思路:大概的思路就是在這張圖片上蓋上一層視圖,視圖裡面有畫兩個圓,內圓是顯示加載進度的,顯示的顏色是
做Android開發的童靴們肯定對系統自帶的控件使用的都非常熟悉,比如Button、TextView、ImageView等。如果你問我具體使用,我會給說:拿ImageVi