【译】一文带你了解Android中23个关于Canvas绘制的方法

原作者:Elye
地址:http://suo.im/5ZrCzC
译者:依然范特稀西

如果你想从头开始在Android中创建自定义View,那么你最好先了解Canvas上有哪写可用于绘制的方法。

在本文中,我将列出23个在Android Canvas 上可以绘制的方法,当你看到它们时,你可能会发现一些自己以前不知道的东西(我也对其中的一些方法感到惊讶!)

如下所示,我将它们分为了4类:

  • 1、几何图形绘制
  • 2、文本绘制
  • 3、颜色绘制
  • 4、图片绘制

接下来,我们一一介绍一下这些方法。

几何图形绘制

多数人使用Canvas来绘制几何图形

1. drawLine

简单的绘制一条线

canvas.drawLine(startX, startY, endX, endY, paint)
2. drawLines

如果你想要绘制多条线,相比于多次执行drawLine,我们推荐使用drawLines来完成,我们只需要提供一个坐标值的平面float数组列表,如下所示。

canvas.drawLines(
    floatArrayOf(
        startFirstX, startFirstY, endFirstX, endFirstY,
        startSecondX, startSecondY, endSecondX, endSecondY),
    paint)
3. drawPoint

虽然您可以通过以相同的起点和终点坐标画一条线来画点,这是一种技巧。我们可以使用专门提供的绘制点的方法,drawPoint函数。

canvas.drawPoint(coordinateX, coordinateY, paint)
4. drawPoints

lines一样,你可以通过提供一个平面坐标数组来绘制多个点。

canvas.drawPoints(
    floatArrayOf(
        startX, startY,
        startSecondX, startSecondY),
    paint)
5. drawRect

使用坐标或Rect类绘制矩形。

canvas.drawRect(
    Rect(startX, topY, endX, bottomY), 
    paint)
6. drawRoundRect

如果你想要绘制一个圆角矩形,可以使用drawRoundRect,它和drawRect法法很像,但是增加了两个参数radiusXradiusY来定义圆角的弯曲程度。

canvas.drawRoundRect(rect, radiusX, radiusY, projectResources.paint)

如果radiusX等于radiusY,它将绘制均匀的圆角。

radiusX = radiusY时,它将具有常规的圆角,如下所示:

如果radiusX 大于 radiusY 时,就会出现下面这样的效果:

如果radiusX 小于 radiusY 时,又变成了这样:

7. drawCircle

drawCircle非常简单,它只需要一个圆心坐标和半径。

canvas.drawCircle(
    centerCoordinateX, centerCoordinateY,
    radius,
    paint)
8. drawOval

不像绘制圆形那样,绘制椭圆时,我们不需要提供半径,而是提供一个rect,然后椭圆就会被正确绘制

canvas.drawOval(rect, paint)
9. drawArc

绘制弧形和绘制椭圆时一样的机制,使用rect,它还增加了几个参数:startAnglesweepAngleuseCenter

canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint)

对于startAngle,将rect的中间端作为起点,即顺时针90°。从那里开始,startAngle被认为是。然后从startAngle计算sweepAngle。两者都使用角度度°值。

useCenter是一个布尔变量,用于确定圆弧是否连接到中心。下图说明了useCenterfalsetrue之间的区别。

useCenter = false:

useCenter = true :

10. drawPath

有时候,我们想画一些不限于普通几何线的东西,我们可以使用drawPath,这里的Path是一个包含了我们想要绘制路径的一个对象,它由铅笔画和移动之类的功能如moveTolineTo组成。

以下是我们绘制十字标记的路径的示例

val path = Path()
path.moveTo(startX, topY)
path.lineTo(endX, bottomY)
path.moveTo(startX, bottomY)
path.lineTo(endX, topY)
canvas.drawPath(path, paint)

drawPath是一个非常有用的功能。许多人使用它在Android中制作绘图应用程序。

11. drawVertices

这是一个相对复杂的函数,它以最小的点绘制三角形或顶点。例如,使用六个坐标,一个可以绘制四个三角形:

重复使用时,可用于复杂的3D建模。下面的艺术品(3D玫瑰)是使用drawVertices绘制的。
[图片上传失败...(image-230e40-1583247600593)]

更详细的说明可以看:https://proandroiddev.com/playing-with-android-canvas-drawvertices-32266c480ab6

Text Drawing

如果我们必须自己绘制文本,那将是非常棘手的。幸运的是,我们有几个不错的选择:

12. drawText

在Android中,我们一般使用TextView 来显示文本,但是如果你要更好的控制文本的话,如:动态更换,精准定位等等。Canvas的drawText就派上了用场。

方法如下,有textcoordinatepaint

canvas.drawText(text, coordinateX, coordinateY, paintText)

如果设置正确,这些将很有趣,如下所示

[图片上传失败...(image-7be96a-1583247600593)]

13. Draw StaticLayout

drawText有局限性。它不会将较长的单词包装到第二行。它也不处理/n进位返回

因此,我们需要一个可将长字换行的文本到第二行来绘制的StaticLayout

StaticLayout实际上并不是Canvas的绘制函数,而是将自身绘制到画布中。下面是它的绘制方式:

val staticLayout =
    StaticLayout.Builder.obtain(
        TEXT, 0, TEXT.length, textPaint, width
    ).build()

canvas.save()
canvas.translate(coordinateX, coordinateY)
staticLayout.draw(canvas)
canvas.restore()

结果如下:

14. drawPosText

drawPosText使每个字符都可以放置在指定位置。在下面,单词fly被写在不同的Y位置。

API如下所示:

val posArray = listOf(x1, y1, x2, y2, x3, y3 ...).toFloatArray()
canvas.drawPosText(TEXT, startIndex, endIndex, posArray, paint)

提供的坐标点必须至少与要绘制的字母相同,否则将崩溃。文档说明:

[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

在绘制文本的基础上加上一个路径,我们就可以沿着提供的path来绘制文本,xy的位置相对于path给定的位置。

canvas.drawTextOnPath(TEXT, path, x, y, paint)

下面是一个V字行的路径,我们沿着path绘制文本。

16. drawTextRun

这个绘制方法就有点复杂了,因为它通常不与英语单词一起使用。它仅适用于其字母根据周围字母的可见性而绘制不同的语言。

例如,下图有两行两个字母。这两行中的两个字母相同。但是,它们的写法不同。在第一行中,它们是较大单词的一部分,而在第二行中,则分别声明了两个字母。

Color Drawing

上色对于我们正在绘制的画布的前景和背景很有用。一起来看看吧...

17. drawRGB

这个方法仅是在画布canvas上绘制颜色,这对于设置背景色非常有用

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.

这对于设置正面颜色并使后面的项目变暗很有用。

正常图片:

设置了红色透明度的图片:

19. drawColor

使用这个方法,我们可以使用颜色资源来代替ARGB颜色,用下面这个API:

canvas.drawColor(context.getColor(R.color.colorPrimary))
20. drawPaint

有时,我们喜欢画一些奇特的颜色。代替使用ARGB或资源颜色,我们可以创建一个Paint对象。下面是一个示例:

val gradientPaint by lazy {
    Paint().apply {
        shader = RadialGradient(
            width/2f,
            height/2f,
            height/2f,
            Color.GREEN,
            Color.RED,
            Shader.TileMode.MIRROR
        )
    }
canvas.drawPaint(gradientPaint)

绘制图片

如果无法加载图像以进行绘制和处理,则cavans绘制将是不完整的。因此,让我们探索一下我们可以做些啥。

21. drawBitmap

给一个bitmap,我们可以将它绘制到画布上

private val bitmap by lazy {
    BitmapFactory.decodeResource(resources, R.drawable.image)
}
canvas.drawBitmap(bitmap, sourceRect, destRect, paint)

必须的参数是bitmapdestRect:

  • bitmap 可以从资源文件加载
  • destRect 是画布上将要绘制的矩形区域

可选择的参数(可以为null)是sourceRectpaint

22. drawPicture

如果你想要绘制的东西组合在一起,并且要多次执行,并且您不希望处理变慢并且必须重新绘制每个时间,则可以将整个图形放入“图片(Picture)”中。

下面是一个简单的示例,其中我们将图形存储到图片中:

private val picture by lazy {
    val picture = Picture()
    val pCanvas = picture.beginRecording(width, height)
    pCanvas.drawBitmap(bitmap, null, rect, null)
    picture.endRecording()
    picture
}

需要时,只需执行这行代码:

canvas.drawPicture(picture)

这样可以加快整个绘制过程的速度,以完成需要一遍又一遍的绘制。

23. drawBitmapMesh

这是为了操纵绘制的位图图像。给定一个图像,我们可以在图像内设置坐标,然后将一个点平移到另一个位置,从而转换它的图像。

例如。下图的中心X,Y显示在白线横截面中。

然而,使用drawBitmapMesh,我们可以移动坐标并相应地变换图像。

可以看下这篇博客了解详情;https://proandroiddev.com/transforming-picture-with-android-canvas-drawbitmapmesh-35f359235774

所有示例代码可以看Github:https://github.com/elye/demo_android_canvas_draw

玩转Android ``Canvas绘图吧!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容