原作者:Elye
地址:http://suo.im/5ZrCzC
譯者:依然范特稀西
如果你想從頭開始在Android中創(chuàng)建自定義View,那么你最好先了解Canvas上有哪寫可用于繪制的方法。
在本文中,我將列出23個(gè)在Android Canvas 上可以繪制的方法,當(dāng)你看到它們時(shí),你可能會(huì)發(fā)現(xiàn)一些自己以前不知道的東西(我也對(duì)其中的一些方法感到驚訝!)
如下所示,我將它們分為了4類:
- 1、幾何圖形繪制
- 2、文本繪制
- 3、顏色繪制
- 4、圖片繪制
接下來,我們一一介紹一下這些方法。
幾何圖形繪制
多數(shù)人使用Canvas來繪制幾何圖形
1. drawLine
簡(jiǎn)單的繪制一條線
canvas.drawLine(startX, startY, endX, endY, paint)

2. drawLines
如果你想要繪制多條線,相比于多次執(zhí)行drawLine,我們推薦使用drawLines來完成,我們只需要提供一個(gè)坐標(biāo)值的平面float數(shù)組列表,如下所示。
canvas.drawLines(
floatArrayOf(
startFirstX, startFirstY, endFirstX, endFirstY,
startSecondX, startSecondY, endSecondX, endSecondY),
paint)

3. drawPoint
雖然您可以通過以相同的起點(diǎn)和終點(diǎn)坐標(biāo)畫一條線來畫點(diǎn),這是一種技巧。我們可以使用專門提供的繪制點(diǎn)的方法,drawPoint函數(shù)。
canvas.drawPoint(coordinateX, coordinateY, paint)
4. drawPoints
和lines一樣,你可以通過提供一個(gè)平面坐標(biāo)數(shù)組來繪制多個(gè)點(diǎn)。
canvas.drawPoints(
floatArrayOf(
startX, startY,
startSecondX, startSecondY),
paint)
5. drawRect
使用坐標(biāo)或Rect類繪制矩形。
canvas.drawRect(
Rect(startX, topY, endX, bottomY),
paint)

6. drawRoundRect
如果你想要繪制一個(gè)圓角矩形,可以使用drawRoundRect,它和drawRect法法很像,但是增加了兩個(gè)參數(shù)radiusX和radiusY來定義圓角的彎曲程度。
canvas.drawRoundRect(rect, radiusX, radiusY, projectResources.paint)
如果radiusX等于radiusY,它將繪制均勻的圓角。

當(dāng)radiusX = radiusY時(shí),它將具有常規(guī)的圓角,如下所示:

如果radiusX 大于 radiusY 時(shí),就會(huì)出現(xiàn)下面這樣的效果:

如果radiusX 小于 radiusY 時(shí),又變成了這樣:

7. drawCircle
drawCircle非常簡(jiǎn)單,它只需要一個(gè)圓心坐標(biāo)和半徑。
canvas.drawCircle(
centerCoordinateX, centerCoordinateY,
radius,
paint)

8. drawOval
不像繪制圓形那樣,繪制橢圓時(shí),我們不需要提供半徑,而是提供一個(gè)rect,然后橢圓就會(huì)被正確繪制
canvas.drawOval(rect, paint)

9. drawArc
繪制弧形和繪制橢圓時(shí)一樣的機(jī)制,使用rect,它還增加了幾個(gè)參數(shù):startAngle,sweepAngle和useCenter。
canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint)
對(duì)于startAngle,將rect的中間端作為起點(diǎn),即順時(shí)針90°。從那里開始,startAngle被認(rèn)為是0°。然后從startAngle計(jì)算sweepAngle。兩者都使用角度度°值。
useCenter是一個(gè)布爾變量,用于確定圓弧是否連接到中心。下圖說明了useCenter為false和true之間的區(qū)別。
useCenter = false:

useCenter = true :

10. drawPath
有時(shí)候,我們想畫一些不限于普通幾何線的東西,我們可以使用drawPath,這里的Path是一個(gè)包含了我們想要繪制路徑的一個(gè)對(duì)象,它由鉛筆畫和移動(dòng)之類的功能如moveTo和lineTo組成。
以下是我們繪制十字標(biāo)記的路徑的示例
val path = Path()
path.moveTo(startX, topY)
path.lineTo(endX, bottomY)
path.moveTo(startX, bottomY)
path.lineTo(endX, topY)
canvas.drawPath(path, paint)

drawPath是一個(gè)非常有用的功能。許多人使用它在Android中制作繪圖應(yīng)用程序。
11. drawVertices
這是一個(gè)相對(duì)復(fù)雜的函數(shù),它以最小的點(diǎn)繪制三角形或頂點(diǎn)。例如,使用六個(gè)坐標(biāo),一個(gè)可以繪制四個(gè)三角形:

重復(fù)使用時(shí),可用于復(fù)雜的3D建模。下面的藝術(shù)品(3D玫瑰)是使用drawVertices繪制的。
[圖片上傳失敗...(image-230e40-1583247600593)]
更詳細(xì)的說明可以看:https://proandroiddev.com/playing-with-android-canvas-drawvertices-32266c480ab6
Text Drawing
如果我們必須自己繪制文本,那將是非常棘手的。幸運(yùn)的是,我們有幾個(gè)不錯(cuò)的選擇:
12. drawText
在Android中,我們一般使用TextView 來顯示文本,但是如果你要更好的控制文本的話,如:動(dòng)態(tài)更換,精準(zhǔn)定位等等。Canvas的drawText就派上了用場(chǎng)。
方法如下,有text,coordinate和paint。
canvas.drawText(text, coordinateX, coordinateY, paintText)
如果設(shè)置正確,這些將很有趣,如下所示
[圖片上傳失敗...(image-7be96a-1583247600593)]
13. Draw StaticLayout
drawText有局限性。它不會(huì)將較長(zhǎng)的單詞包裝到第二行。它也不處理/n進(jìn)位返回
因此,我們需要一個(gè)可將長(zhǎng)字換行的文本到第二行來繪制的StaticLayout 。
StaticLayout實(shí)際上并不是Canvas的繪制函數(shù),而是將自身繪制到畫布中。下面是它的繪制方式:
val staticLayout =
StaticLayout.Builder.obtain(
TEXT, 0, TEXT.length, textPaint, width
).build()
canvas.save()
canvas.translate(coordinateX, coordinateY)
staticLayout.draw(canvas)
canvas.restore()
結(jié)果如下:

14. drawPosText
drawPosText使每個(gè)字符都可以放置在指定位置。在下面,單詞fly被寫在不同的Y位置。

API如下所示:
val posArray = listOf(x1, y1, x2, y2, x3, y3 ...).toFloatArray()
canvas.drawPosText(TEXT, startIndex, endIndex, posArray, paint)
?
提供的坐標(biāo)點(diǎn)必須至少與要繪制的字母相同,否則將崩潰。文檔說明:
[This API is deprecated] because this method does not support glyph composition and decomposition and should therefore not be used to render complex scripts. It also doesn’t handle supplementary characters
15. drawTextOnPath
在繪制文本的基礎(chǔ)上加上一個(gè)路徑,我們就可以沿著提供的path來繪制文本,x和y的位置相對(duì)于path給定的位置。
canvas.drawTextOnPath(TEXT, path, x, y, paint)
下面是一個(gè)V字行的路徑,我們沿著path繪制文本。

16. drawTextRun
這個(gè)繪制方法就有點(diǎn)復(fù)雜了,因?yàn)樗ǔ2慌c英語(yǔ)單詞一起使用。它僅適用于其字母根據(jù)周圍字母的可見性而繪制不同的語(yǔ)言。
例如,下圖有兩行兩個(gè)字母。這兩行中的兩個(gè)字母相同。但是,它們的寫法不同。在第一行中,它們是較大單詞的一部分,而在第二行中,則分別聲明了兩個(gè)字母。

Color Drawing
上色對(duì)于我們正在繪制的畫布的前景和背景很有用。一起來看看吧...
17. drawRGB
這個(gè)方法僅是在畫布canvas上繪制顏色,這對(duì)于設(shè)置背景色非常有用
canvas.drawRGB(red, green, blue)
// Each is between 0 and 255, where 0 is not there, and 255 is full.
// When alpha is 255, it is opaque, and 0 is transparent.
18. drawARGB
和drawRGB相似,drawARGB增加了使顏色有透明度的能力。
canvas.drawARGB(alpha, red, green, blue)
// When alpha is 255, it is opaque, and 0 is transparent.
這對(duì)于設(shè)置正面顏色并使后面的項(xiàng)目變暗很有用。
正常圖片:

設(shè)置了紅色透明度的圖片:

19. drawColor
使用這個(gè)方法,我們可以使用顏色資源來代替ARGB顏色,用下面這個(gè)API:
canvas.drawColor(context.getColor(R.color.colorPrimary))
20. drawPaint
有時(shí),我們喜歡畫一些奇特的顏色。代替使用ARGB或資源顏色,我們可以創(chuàng)建一個(gè)Paint對(duì)象。下面是一個(gè)示例:
val gradientPaint by lazy {
Paint().apply {
shader = RadialGradient(
width/2f,
height/2f,
height/2f,
Color.GREEN,
Color.RED,
Shader.TileMode.MIRROR
)
}
canvas.drawPaint(gradientPaint)

繪制圖片
如果無法加載圖像以進(jìn)行繪制和處理,則cavans繪制將是不完整的。因此,讓我們探索一下我們可以做些啥。
21. drawBitmap
給一個(gè)bitmap,我們可以將它繪制到畫布上
private val bitmap by lazy {
BitmapFactory.decodeResource(resources, R.drawable.image)
}
canvas.drawBitmap(bitmap, sourceRect, destRect, paint)
必須的參數(shù)是bitmap 和 destRect:
-
bitmap可以從資源文件加載 -
destRect是畫布上將要繪制的矩形區(qū)域
可選擇的參數(shù)(可以為null)是sourceRect 和paint:
-
sourceRect是一個(gè)矩形,代表要繪制圖片的哪個(gè)子集。如果為空,則拍攝整個(gè)照片(注意:這對(duì)于某些動(dòng)畫非常有用,比如要添加整個(gè)動(dòng)畫圖形的圖片,并且一次只顯示一個(gè)子集時(shí)。) -
paint可以設(shè)置為null,并且位圖將照常繪制。如果我們計(jì)劃用另一幅圖像將其遮蔽,則paint很有用。此StackOverflow中顯示了一個(gè)示例:https://stackoverflow.com/questions/23966272/android-mask-bitmap-on-canvas-gen-a-black-space/26031133#26031133
22. drawPicture
如果你想要繪制的東西組合在一起,并且要多次執(zhí)行,并且您不希望處理變慢并且必須重新繪制每個(gè)時(shí)間,則可以將整個(gè)圖形放入“圖片(Picture)”中。
下面是一個(gè)簡(jiǎn)單的示例,其中我們將圖形存儲(chǔ)到圖片中:
private val picture by lazy {
val picture = Picture()
val pCanvas = picture.beginRecording(width, height)
pCanvas.drawBitmap(bitmap, null, rect, null)
picture.endRecording()
picture
}
需要時(shí),只需執(zhí)行這行代碼:
canvas.drawPicture(picture)
這樣可以加快整個(gè)繪制過程的速度,以完成需要一遍又一遍的繪制。
23. drawBitmapMesh
這是為了操縱繪制的位圖圖像。給定一個(gè)圖像,我們可以在圖像內(nèi)設(shè)置坐標(biāo),然后將一個(gè)點(diǎn)平移到另一個(gè)位置,從而轉(zhuǎn)換它的圖像。
例如。下圖的中心X,Y顯示在白線橫截面中。

然而,使用drawBitmapMesh,我們可以移動(dòng)坐標(biāo)并相應(yīng)地變換圖像。

可以看下這篇博客了解詳情;https://proandroiddev.com/transforming-picture-with-android-canvas-drawbitmapmesh-35f359235774
所有示例代碼可以看Github:https://github.com/elye/demo_android_canvas_draw
玩轉(zhuǎn)Android ``Canvas繪圖吧!