圖形繪製簡介
Android中使用圖形處理引擎,2D部分是android SDK內部本身提供,3D部分是用Open GL ES 1.0。 大部分2D使用的api都在android. graphics和android.graphics.drawable包中。他們提供了圖形處理相關的Canvas、ColorFilter、Point、RetcF等類,還有一些動畫相關的AnimationDrawable、BitmapDrawable、TransitionDrawable等。
以圖形處理來講,咱們最經常使用到的就是在一個View上畫一些圖片、形狀或者自定義的文本內容,這些都是使用Canvas來實現的。另外,咱們 能夠獲取View中的Canvas對象,在繪製一些內容後調用 View.invalidate 方法讓View從新刷新,而後再繪製一個新的內容,以此屢次以後,就實現了2D動畫的效果。
畫圖須要四大基本要素:一、一個用來保存像素的Bitmap二、一個或多個畫筆Paint三、須要繪製的內容四、一個Canvas畫布,用來在Bitmap上使用Paint繪製內容
Canvas對象的獲取方式
Canvas對象的獲取方式有三種:一、經過重寫View.onDraw方法獲取Canvas對象。
這種方式根據環境還分爲兩種:一種是普通View的Canvas,還有一種是SurfaceView的Canvas。兩種的主要是區別就是,能夠在SurfaceView中定義一個專門的線程來完成畫圖工做,應用程序不須要等待View的刷圖,提升性能。前面一種適合處理量比較小,幀率比較低的動畫方面的繪圖,好比說象棋遊戲之類的;然後一種主要用在遊戲或高品質動畫方面的繪圖。二、直接建立一個Canvas對象:
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);Canvas c = new Canvas(bitmap);上面代碼建立了一個尺寸是100*100的Bitmap,使用它做爲Canvas操做的對象,這時候的Canvas就是使用建立的方式。
當你使用建立的Canvas在bitmap上執行繪製方法後,你還能夠將繪製的結果提交給另一個Canvas,這樣就能夠達到兩個Canvas協做完成的效果,簡化邏輯。可是android SDK建議使用View.onDraw參數裏提供的Canvas就好,不必本身建立一個新的Canvas對象。三、調用SurfaceHolder.lockCanvas()也會返回一個Canvas對象,能夠在 surfaceView 或 TextureView中使用。
Canvas位置裝換、保存、恢復
Android還提供了一些對Canvas位置轉換的方法:rorate、scale、translate、skew(扭曲)等,並且它容許你經過 getMatrix 得到它的轉換矩陣對象,並能夠直接操做它。這些操做就像是雖然你的筆仍是在原來的地方畫,可是畫紙(座標原點)旋轉或者移動了,因此你畫的東西的方位就產生了變化。
爲了方便 使用 這些轉換操做,Canvas 還提供了保存和回滾屬性的方法 save和restore 。 save用來保存Canvas的狀態,save以後,能夠調用Canvas的平移、放縮、旋轉、錯切、裁剪等操做。 restore 用來恢復Canvas以前保存的狀態,防止save後對Canvas執行的操做對後續的繪製有影響。注意:save和restore要配對使用,若是restore調用次數比save多,會引起Error。
小細節上圖,最初始的狀況是棧裏只有 0 1 2 3 4 , 而後執行 save 方法兩次,則 5 和 6 出如今棧中
Canvas可繪製的圖形種類
一、繪製背景(填充)
drawARGB(int a, int r, int g, int b)drawColor(int color)drawRGB(int r, int g, int b)drawColor(int color, PorterDuff.Mode mode)二、 繪製 幾何圖形canvas.drawArc (扇形,弓形, 弧線區域 )canvas.drawCircle(圓)canvas.drawOval(圓和橢圓)canvas.drawLine(線)canvas.drawPoint(點)canvas.drawRect(矩形)canvas.drawRoundRect(圓角矩形)canvas.drawVertices(頂點)cnavas.drawPath(路徑,可用來繪製任意圖形)三、 繪製 圖片canvas.drawBitmap (位圖)canvas.drawPicture (圖片)四、 繪製 文本canvas.drawText
Paint畫筆工具相關設置
Paint即畫筆,在繪圖過程當中起到了極其重要的做用,畫筆主要保存了顏色、 樣式等繪製信息,指定了如何繪製文本和圖形。 畫筆對象有不少設置方法, 大致上能夠分爲兩類:一、圖 形相關的設置方法
- setARGB(int a,int r,int g,int b); 設置繪製的顏色,a表明透明度,r,g,b表明顏色值。
- setAlpha(int a); 設置繪製圖形的透明度。
- setColor(int color); 設置繪製的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
- setAntiAlias(boolean aa); 設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。
- setDither(boolean dither); 設定是否使用圖像抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,圖像更加清晰
- setFilterBitmap(boolean filter); 若是該項設置爲true,則圖像在動畫進行中會濾掉對Bitmap圖像的優化操做,加快顯示速度,本設置項依賴於dither和xfermode的設置
- setMaskFilter(MaskFilter maskfilter); 設置MaskFilter,能夠用不一樣的MaskFilter實現濾鏡的效果,如濾化,立體等
- setColorFilter(ColorFilter colorfilter); 設置顏色過濾器,能夠在繪製顏色時實現不用顏色的變換效果
- setPathEffect(PathEffect effect); 設置繪製路徑的效果,如點畫線等
- setShader(Shader shader); 設置圖像效果,使用Shader能夠繪製出各類漸變效果
- setShadowLayer(float radius ,float dx,float dy,int color); 在圖形下面設置陰影層,產生陰影效果,radius爲陰影的角度,dx和dy爲陰影在x軸和y軸上的距離,color爲陰影的顏色
- setStyle(Paint.Style style); 設置畫筆的樣式。FILL:實心,默認;FILL_OR_STROKE:填充並設置描邊;STROKE:描邊,空心
- setStrokeCap(Paint.Cap cap); 定義線段斷點形狀。當畫筆樣式爲STROKE或FILL_OR_STROKE時,設置咱們的畫筆在【離開】畫板時候留下的最後一點圖形,如圓形樣式 Cap.ROUND(有延長),或方形樣式Cap.BUTT(默認,沒有延長)與Cap.SQUARE(有延長)
- setSrokeJoin(Paint.Join join); 設置繪製時各圖形的結合方式(圖形節點的樣式),如平滑效果等
- setStrokeWidth(float width); 當畫筆樣式爲STROKE或FILL_OR_STROKE時,設置筆刷的粗細
- setXfermode(Xfermode xfermode); 設置圖形重疊時的處理方式,如合併,取交集或並集
2.文本相關的設置方法
- setFakeBoldText(boolean fakeBoldText); 模擬實現粗體文字,設置在小字體上效果會比較差
- setSubpixelText(boolean subpixelText); 設置該項爲true,將有助於文本在LCD屏幕上的顯示效果
- setTextAlign(Paint.Align align); 設置繪製文字的對齊方向
- setTextScaleX(float scaleX); 設置繪製文字x軸的縮放比例,能夠實現文字拉伸的效果
- setTextSize(float textSize); 設置繪製文字的字號大小
- setTextSkewX(float skewX); 設置斜體文字,skewX爲x軸方向的傾斜弧度
- setTypeface(Typeface typeface); 設置字體風格,包括粗體,斜體以及襯線體,非襯線體等
- setUnderlineText(boolean underlineText); 設置帶有下劃線的文字效果
- setStrikeThruText(boolean strikeThruText); 設置帶有刪除線的效果
代碼-繪製各類圖形
public class TestPaintView extends View {private Context context;private Paint paint;private RectF rect;//Rect是使用int類型做爲數值,RectF是使用float類型做爲數值private Path path;//主要用於繪製複雜的圖形輪廓,好比折線,圓弧以及各類複雜圖案private Bitmap bitmap;private int left, top, right, bottom;
public TestPaintView(Context context) {super(context);this.context = context;paint = new Paint();rect = new RectF(0, 0, 0, 0);//左X、上Y、右X、下Y相應的距離,即左上角、右下角的座標,系統不會檢查數值的有效性paint.setStrokeJoin(Paint.Join.ROUND);//設置繪製時圖形的結合方式(圖形節點的樣式)paint.setStrokeCap(Paint.Cap.ROUND);//設置畫筆在【離開】畫板時留下的最後一點的樣式paint.setAntiAlias(true);paint.setDither(true);paint.setStrokeWidth(dp2px(0.5f));//設置畫筆粗細,單位爲像素bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);}
@SuppressLint("DrawAllocation")@Overrideprotected void onDraw(Canvas canvas) {//背景顏色canvas.drawColor(0x33005500);//矩形initRect(10, 50, 10, 50);paint.setStyle(Paint.Style.STROKE);//描邊(空心),默認是FILL(實心、填充)canvas.drawRect(rect, paint);//繪製弧線區域(扇形或弓形)paint.setStyle(Paint.Style.FILL);paint.setColor(0xff00ff00);canvas.drawArc(rect, 0, 90, false, paint);//當爲false時是一個不通過【圓心】的弓形,當爲true時是一個通過圓心的扇形paint.setColor(0xffff0000);canvas.drawArc(rect, 90, 150, true, paint); //圓弧所在矩形,起始角度90,旋轉角度150,順時針爲正//矩形內切圓(或橢圓)paint.setStyle(Paint.Style.STROKE);initRect(10, 30, 10, 50);canvas.drawRect(rect, paint);paint.setARGB(255, 0, 0, 255);canvas.drawOval(rect, paint);paint.setStyle(Paint.Style.FILL);canvas.drawArc(rect, 0, 90, false, paint); //橢圓的扇形paint.setARGB(128, 255, 0, 255);canvas.drawArc(rect.left, rect.top, rect.right, rect.bottom, 90f, 150f, true, paint);
//圓角矩形paint.setStyle(Paint.Style.STROKE);initRect(10, 50, 10, 50);canvas.drawRoundRect(rect, 20, 20, paint);//矩形,兩側圓角弧度的大小,通常都設爲相同//畫直線canvas.drawLine(dp2px(120), dp2px(25), dp2px(120), dp2px(55), paint);// 畫一條線(首尾兩點的座標)paint.setColor(Color.BLUE);float[] points = new float[] { dp2px(120), dp2px(15), dp2px(150), dp2px(15),//畫多條線。每條線都須要兩個座標(每兩個值組成一個座標)dp2px(130), dp2px(25), dp2px(150), dp2px(55), dp2px(150), dp2px(25) };canvas.drawLines(points, paint);//最後兩個值不夠組成一條線,因此被廢棄掉了。paint.setColor(Color.BLACK);canvas.drawLines(points, 2, 8, paint);//指定跳過前2個數據,取出8個數據繪製直線// 畫圓canvas.drawCircle(dp2px(190), dp2px(35), dp2px(25), paint);//圓心座標,半徑//畫點paint.setStrokeWidth(dp2px(3));canvas.drawPoint(dp2px(190), dp2px(35), paint);//畫一個點paint.setColor(Color.RED);canvas.drawPoints(points, paint);//畫多個點,每兩個值組成一個座標//畫圖片,就是貼圖canvas.drawBitmap(bitmap, dp2px(220), dp2px(10), paint);//座標指的是左上角的位置//canvas.drawCircle(320 + bitmap.getWidth() / 2, 200 + bitmap.getWidth() / 2, bitmap.getWidth() / 2, paint);//*************************************************************************************
//畫路徑1,不規則封閉圖形paint.setStrokeWidth(dp2px(0.5f));path = new Path();path.moveTo(dp2px(10), dp2px(70));//指定初始輪廓點,若沒指定默認從(0,0)點開始path.lineTo(dp2px(10), dp2px(100));//從當前輪廓點繪製一條線段到指定輪廓點path.lineTo(dp2px(50), dp2px(100));path.lineTo(dp2px(50), dp2px(80));path.close(); // 回到初始點造成封閉的曲線canvas.drawPath(path, paint);//畫路徑2,利用path也能夠畫各類圖形,api使用上和canvas有些許區別rect = new RectF(dp2px(60), dp2px(70), dp2px(110), dp2px(120));path.addRect(rect, Direction.CW);//利用path畫矩形。Diection.CW 順時針方向,Diection.CCW 逆時針方向canvas.drawPath(path, paint);paint.setColor(Color.BLUE);//注意,同一path繪製的圖形的顏色必定是相同的Path path2 = new Path();//若是這裏不從新new一個path,則前面用path繪製的圖形的顏色也都會變path2.addRoundRect(rect, new float[] { 20, 60, 20, 60, 60, 60, 20, 20 }, Direction.CW);//從左上角順時針開始,四個角的x軸y軸方向的弧度canvas.drawPath(path2, paint);//繪製文本canvas.drawLine(rect.left, rect.centerY(), rect.right, rect.centerY(), paint);paint.reset();//重置paint.setTextSize(dp2px(12));//單位是px,只在繪製文字時有效paint.setTextAlign(Align.CENTER);//繪製的文字以drawText時指定的 float x 水平居中,默認值是Align.LEFTcanvas.drawText("1efg", rect.centerX(), rect.centerY(), paint);//注意 float y 表明的是 baseline 的值,也即e和f的下邊界,而非g的下邊界paint.setUnderlineText(true);//帶下劃線canvas.drawText("包青天efg", 0, "包青天efg".length(), rect.right + dp2px(30), rect.top + dp2px(12), paint);//(+textSize)可實現和矩形頂部對齊canvas.drawText(new char[] { 'J', '!', '。', '.' }, 0, 4, rect.right + dp2px(30), rect.centerY(), paint);//在指定路徑上繪製文本Path path3 = new Path();path3.moveTo(rect.right, rect.bottom);path3.lineTo(rect.right + dp2px(150), rect.centerY());canvas.drawPath(path3, paint);paint.setTextAlign(Align.LEFT);canvas.drawTextOnPath("123456789", path3, 30, -10, paint);//float hOffset,相對基準線的向右偏移值, float vOffset向下偏移值}
/*** 從新設置矩形邊界* @param leftAdd, 表明新矩形的左邊界距離上一個矩形的右邊界的距離* @param width,表明矩形的寬度* @param topAdd, 表明新矩形的上邊界的值* @param hight,表明矩形的高度*/private void initRect(int leftAdd, int width, int topValue, int hight) {left = right + leftAdd;right = left + width;top = topValue;bottom = top + hight;rect.left = dp2px(left);rect.right = dp2px(right);rect.top = dp2px(top);rect.bottom = dp2px(bottom);}private int dp2px(float dpValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}}
代碼-位置裝換、保存、恢復
public class TestCanvasView extends View {private static final int SAVE_FLAGS = //Canvas.ALL_SAVE_FLAG //= 0x1F,還原全部,restore everything when restore() is calledCanvas.MATRIX_SAVE_FLAG//= 0x01,須要還原Matrix。restore the current matrix when restore() is called| Canvas.CLIP_SAVE_FLAG //= 0x02,須要還原Clip。restore the current clip when restore() is called| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG //=0x04, 圖層的 clip 標記。the layer needs to per-pixel alpha| Canvas.FULL_COLOR_LAYER_SAVE_FLAG//= 0x08,圖層的 color 標記。the layer needs to 8-bits per color component| Canvas.CLIP_TO_LAYER_SAVE_FLAG;// = 0x10,圖層的 clip 標記,在saveLayer 和 saveLayerAlpha時Android強烈建議加上他private Paint mPaint;public TestCanvasView(Context context) {super(context);mPaint = new Paint();mPaint.setAntiAlias(true);}
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.WHITE);//畫一個紅色的圓mPaint.setColor(Color.RED);canvas.drawCircle(100, 100, 100, mPaint);canvas.save();//保存Canvas的狀態,save以後,能夠調用Canvas的平移、放縮、旋轉、錯切、裁剪等操做。save()默認保存的是matrix和clip//畫一個綠色的拉長的圓(即橢圓)canvas.scale(0.5f, 1);//x、y軸的縮放比例mPaint.setColor(Color.GREEN);canvas.drawCircle(100, 100, 100, mPaint);//畫一個黃色的矩形canvas.restore();//restore用來恢復Canvas以前保存的狀態,防止save後對Canvas執行的指定操做對後續的繪製有影響canvas.translate(200, 0);//把畫布平移。此操做對下面新建的那個圖層依然是有效的mPaint.setColor(Color.YELLOW);canvas.drawRect(0, 0, 200, 200, mPaint);canvas.save(SAVE_FLAGS);//指定哪些須要還原。只有指定matrix或clip纔有效,其他幾個參數在saveLayer和saveLayerAlpha方法中才有效
//畫一個藍色的扭曲的矩形canvas.skew(2f, 1);//圖形變換惟一規則:將x座標所有變爲*2,將y座標所有變爲*1。至因而否平行啦之類的都不去限制。mPaint.setColor(Color.BLUE);canvas.drawRect(0, 0, 100, 100, mPaint);//畫一個帶透明度的藍色的旋轉的小矩形canvas.restore();//取消扭曲。canvas.translate(200, 0);canvas.rotate(30, 50, 50);//沿指定點爲中心順時針旋轉指定角度。默認是以左上角爲中心int count = canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, SAVE_FLAGS);//在指定邊界新建一個透明度爲0x88的圖層canvas.drawRect(0, 0, 100, 100, mPaint);//繪製時使用的顏色還是上次的藍色,而非save以前的顏色。這個圖層的透明度對此圖形是有影響的//畫一個綠色的小圓canvas.restore();canvas.restore();//若是restore調用的次數大於save的調用次數,會出錯。canvas.restoreToCount(count);mPaint.setColor(Color.GREEN);canvas.drawCircle(50, 50, 50, mPaint);// 這個圓是在原來的圖層上劃的, 沒有透明度}}