做者:宋者爲王html
鏈接:https://cnblogs.com/andy-songwei/p/10960012.htmlcanvas
上一篇講 View 的繪製流程中講到過,最後一步是 draw 流程,在這個過程當中,子 view 須要重寫 onDraw 方法來畫出本身的內容。在自定義 View 繪製自身內容的時候,系統提供了 3 個很是重要的類來幫助開發者畫各類炫酷的圖形:Canvas、Paint、Path。本篇主要介紹 Canvas 相關的內容,Paint 和 Path 在後面會單獨再作介紹。官方文檔中介紹的 Canvas 相關的 API 不少,本文主要介紹和梳理一些比較經常使用的實用功能。數組
本文的主要內容以下:app
以下代碼展現了一個自定義 view 畫圖形的一個很是簡單的示例。這裏 onDraw 方法的參數 Canvas 就是本篇的主角了,中文意思「畫布」,意思就是全部「畫」的內容都是在這張畫布上完成的。ide
Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 繪製一個原點座標(300,300),半徑爲200的圓
canvas.drawCircle(300, 300, 200, paint);
}
代碼很是簡單,可見自定義繪製上手很是容易。函數
Canvas 包含了一些畫基本圖案的函數,基本都是以 drawXXX 的形式給出的。post
這裏先簡單介紹一下畫圖中所參照的座標系,是以當前 View 位置的左上角爲原點(0,0),水平方向向右爲 X 軸正方向,豎直向下爲 Y 軸正方向,這裏的 View 位置是個相對值,它取決於開發者把它放在哪裏。座標系大體以下所示,注意和平時咱們數學上座標系略有差異。spa
在 Canvas 的這些 drawXXX 方法中會用到 paint 類,它是畫筆,會決定繪製出來的圖形的顏色,是填充整個圖形仍是僅繪製邊框線條等多個屬性。這些會在之後專門介紹 Paint 的時候再講,這裏先提醒讀者注意,在筆者截取的效果圖中,我們這裏先只關注形狀,關於 piant,一概先用默認的填充。3d
函數原型:drawColor(@color int color)。rest
做用:將整個繪製區域填充爲指定顏色(能夠設置透明度)。
示例:通常有三種方式來引用顏色值
//使用系統提供的顏色
canvas.drawColor(Color.BLACK);
//使用自定義顏色
canvas.drawColor(Color.parseColor("#000000"));
//使用color.xml中定義的顏色值
canvas.drawColor(getResources().getColor(R.color.black));
其它設置顏色的方法
1)drawRGB(int r, int g, int b):根據 RGB 值來設置顏色
2)drawARGB(int a, int r, int g, int b):根據透明度和 RGB 的值來設置顏色。
上述中的幾種方法,適用於在繪製前設置底色,或者在繪製完成後添加一層半透明蒙板。
函數原型 drawCircle(float centerX, float centerY, float radius, Paint paint)。參數依次爲:X 座標,Y 座標,半徑,畫筆。
做用:以原點(centerX,centerY),半徑 radius,畫一個圓。
示例:
// 繪製一個原點座標(300,300),半徑爲200的圓
canvas.drawCircle(300, 300, 200, paint);
函數原型:drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) 參數分別爲左邊、頂部、右邊、底部四條邊的座標值。
根據給定的 4 條邊框的座標,來畫矩形。
示例:
canvas.drawRect(100, 100, 500, 500, paint);
其餘函數
1) drawRect(@NonNull Rect r, @NonNull Paint paint)。實際上就是將前面函數定義爲一個 Rect 來做爲參數,做用和上面同樣。
2)示例,效果和上述同樣。
canvas.drawRect(new Rect(100,100,500,500),mPaint);
函數原型:drawPoint(float x, float y, @NonNull Paint paint)。參數 x,y 分別爲該點的座標,點的大小和形狀由 paint 決定。
功能:在指定 x,y 座標處畫點
示例
canvas.drawPoint(50, 50, paint);
drawPoints(float[] pts, int offset, int count,@NonNull Paint paint)。pts 這個數組是點的座標,每兩個成一對;offset 表示跳過數組的前幾個數再開始記座標;count 表示一共有多個數參與繪製。
示例:
float[] points = {0, 0, 50, 50, 50, 100, 100, 50, 100, 100, 150, 50};
canvas.drawPoints(points, 2 /* 跳過兩個數,即前兩個 0 */,
8 /* 一共繪製 8 個數(4 個點)*/, paint);
函數原型:drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)。參數分別爲四個頂點所在切線座標。
做用:4 個參數肯定了一個矩形的 4 條邊框,這個矩形肯定了一個橢圓。該函數用於畫出這個指定的橢圓。
示例
canvas.drawOval(50, 50, 350, 200, paint);
函數原型:drawLine(float startX, float startY, float stopX, float stopY, Paint paint)。參數值分別爲起始點座標和結束點座標。
做用:根據給定的起始點和結束點畫直線
示例
canvas.drawLine(200, 200, 800, 500, paint);
函數原型:drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint)。扇形或者弧線,都是橢圓(圓能夠當作是橢圓的特殊情形)上的一部分,因此畫扇形或者弧線須要先肯定好橢圓,前 4 個參數就是用於肯定這個橢圓。startAngle 表示起始角度,X 軸正方向(即水平向右方向)爲 0 度,順時針爲正角度,逆時針爲負角度。sweepAngle 表示弧線/扇形劃過的角度,依然是順時針爲正,逆時針爲負;useCenter 表示是否連到圓心,true 表示連到,表示扇形,false 表示不連到,表示弧線。
示例:
canvas.drawArc(200, 100, 800, 500, -110, 100, true, paint); // 繪製扇型
canvas.drawArc(200, 100, 800, 500, 20, 140, false, paint); // 繪製弧形
函數原型:drawPath(Path path, Paint paint)
根據 path 定義的形狀來繪製。這個會在後續文章中詳細講。
函數原型:drawBitmap(Bitmap bitmap, float left, float top, Paint paint)。參數 bitmap 表示要繪製的圖片對象;left,top 表示要顯示的 bitmap 對象的左上角左邊位置。
做用:把指定的 bitmap 對象中的像素複製到指定位置。
示例:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test);
canvas.drawBitmap(bitmap,100,50,paint);
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint);
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint);
drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint);
它們能夠指定複製原 bitmap 中的指定區域(Rect src 來肯定),到畫布中的指定位置(Rect dst)來肯定。
函數原型:drawText(String text, float x, float y, Paint paint)。界面裏全部的顯示內容,都是繪製出來的,包括文字。drawText() 這個方法就是用來繪製文字的。參數 text 是用來繪製的字符串, x 和 y 是繪製的起點座標。文字的繪製在後面也會單獨詳細說明。
根據給定的範圍,對指定的 bitmap 進行裁剪,裁剪以後再進行繪製。範圍裁剪有兩個方法:clipRect()和 clipPath()。前者會截取一個矩形範圍,然後者 path 指定的形狀更多,因此裁剪的形狀也會更多。
在裁剪的過程當中,要加上這兩句代碼。它們用於保存和恢復繪製範圍,若是不加容易出現干擾。
canvas.save();
//目標bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test);
//肯定須要裁剪的矩形範圍
canvas.clipRect(left, top, right, bottom);
//在指定的x,y座標開始繪製裁剪後的bitmap
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
裁剪後的效果以下圖所示:
Canvas.clipRect(Path path) 用法徹底同樣,只是把參數換成了 Path ,因此能裁切的形狀更多一些。其對應有一個方法 Canvas.clipOutPaht(Path path),反向裁剪,效果能夠從截圖中看出來。
canvas.save();
canvas.clipPath(path1);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
canvas.save();
canvas.clipOutPath(path);
canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
canvas.restore();
這個功能對顯示原型頭像比較有幫助。
幾何變換的使用大概分爲三類:使用 Canvas 來作常見的二維變換;使用 Matrix 來作常見和不常見的二維變換;使用 Camera 來作三維變換。
Canvas.translate(float dx, float dy) 平移。參數裏的 dx 和 dy 表示橫向和縱向的位移。
Canvas.rotate(float degrees, float px, float py) 旋轉
Canvas.scale(float sx, float sy, float px, float py)放大縮小
Canvas.skew(float sx, float sy) 錯切,就是傾斜的意思。
canvas.save();
//水平向X軸正方向移動200px
canvas.translate(200, 0);
//以給定的點爲軸旋轉45度
canvas.rotate(45, centerX, centerY);
//以圖片中心爲軸,水平和豎直方向各放大爲原來的1.3倍
canvas.scale(1.3f, 1.3f, x + bitmapWidth / 2, y + bitmapHeight / 2);
canvas.skew(0, 0.5f);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
使用 Matrix 能夠作常規的幾何變換,還能夠對圖形進行自定義變換。在作常規的幾何變換時,和前面介紹的用 Canvas 實現常規變換,功能同樣,選其一便可。
使用 Matrix 來作常規變換主要分三個步驟:
建立Matrix對象;
Matrix.pre/postTranslate/Rotate/Scale/Skew()設置幾何變換;
Canvas.setMatrix(matrix)或Canvas.concat(matrix)把幾何變換應用到Canvas中(儘可能用後者)。
//1.建立Matrix對象
Matrix matrix = new Matrix();
matrix.reset();
//2.幾何變換
matrix.postTranslate(0,100);
matrix.postRotate(45,bitmap.getWidth()/2,bitmap.getHeight()/2);
matrix.postScale(1.3f,1.3f,x+bitmap.getWidth()/2,y+bitmap.getHeight()/2);
matrix.postSkew(0,0.5f);
canvas.save();
//3.把幾何變換應用到Canvas中
canvas.concat(matrix);
canvas.drawBitmap(bitmap,x,y,paint1);
canvas.restore();