参考:

关于绘图相关的 Paint、Canvas多少都接触过一些,但没有系统的学习过,每次都是边查边用,这里都是参考大神的博客而成的学习记录,(采用Kotlin语言,来编写,kotlin确实有些坑,但不妨碍学习),同时将心得与组内开发人员一起学习,分享;

1. Paint与Canvas

Paint是画笔,Canvas是布,程序中为画布;

跟要要画的东西的设置相关的,比如大小,粗细,画笔颜色,透明度,字体的样式等等,都是在Paint里设置;

凡是要画出成品的东西,比如圆形,矩形,文字等相关的都是在Canvas里生成;

Paint 基本设置函数:

paint.setAntiAlias(true);//抗锯齿功能

paint.setColor(Color.RED); //设置画笔颜色

paint.setStyle(Style.FILL);//设置填充样式,Style.STOKE 为空心

paint.setStrokeWidth(30);//设置画笔宽度

paint.setShadowLayer(10, 15, 15, Color.GREEN);//设置阴影

以上几个方法除setShadowLayer都好理解,不做过多解释;setShadowLayer签名为:

/**

* radius:阴影的倾斜度

* dx:水平位移

* dy:垂直位移

*/

public void setShadowLayer(float radius, float dx, float dy, int shadowColor)

Canvas的基本设置:

canvas.drawColor(Color.BLUE);

canvas.drawRGB(255, 255, 0); //这两个功能一样,都是用来设置背景颜色

2. 基本几何图形绘制

单条直线与多条直线

我们知道,确定一条直线,需要2个点,所以此方法API与此定义一致如:

// 方法签名

public void drawLine(float startX, float startY, float stopX, float stopY,

@NonNull Paint paint) {...}

// 使用

canvas.drawLine(0f,0f, 100f, 10f, paint)

多条直线

public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint)

public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,

@NonNull Paint paint)

参数:

pts为一系列点的集合,至少要有4个点,他们不是连接线,而是每2个点形成一条直线;

// multi line

val pts = floatArrayOf(200f, 350f, 230f, 400f, 250f, 450f, 300f, 500f)

canvas.drawLines(pts, paint)

单个点与多个点

// 单个点

public void drawPoint(float x, float y, @NonNull Paint paint)

// 多个点

public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint)

public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,

@NonNull Paint paint)

参数:

offset:集合中跳过的数值个数,注意不是点的个数!一个点是两个数值;

count:参与绘制的数值的个数,指pts[]里人数值个数,而不是点的个数,因为一个点是两个数值;

val paint2 = Paint(Paint.ANTI_ALIAS_FLAG).apply {

color = Color.GREEN

style = Paint.Style.FILL

strokeWidth = 20f

}

canvas.drawPoint(500f, 500f, paint2)

val points = floatArrayOf(550f, 550f, 550f, 600f, 500f, 650f, 500f, 700f)

// 跳过2个数值,然后用后面6个点,来画poiner,也就是最后3个点,

// 如果count传入4,即最后一个不画,传大于6的数,奔溃(ArrayIndexOutOfBoundsException),

// 因为8个数,除去2个数外,只有6个数了;

canvas.drawPoints(points, 2, 6, paint2)

矩形工具类RectF与Rect

根据四个点构建一个矩形结构;在画图时,利用这个矩形结构可以画出对应的矩形或者与其它图形Region相交、相加等等;

Region部分,后面细说;

圆角矩形

public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)

参数:

rx,ry 表示生成圆角的椭圆的X|Y轴半径

画圆

很好理解,确定圆心与半径;

椭圆

椭圆是根据矩形生成的,以矩形的长为椭圆的X轴,矩形的宽为椭圆的Y轴,建立的椭圆图形;

val paint = Paint().apply {

color = Color.RED

style = Paint.Style.STROKE//填充样式改为描边

strokeWidth = 5f//设置画笔宽度

}

val rect = RectF(100f, 10f, 600f, 300f)

canvas.drawRect(rect, paint)//画矩形

paint.color = Color.GREEN//更改画笔颜色

canvas.drawOval(rect, paint)//同一个矩形画椭圆

oval

弧是椭圆的一部分,而椭圆是根据矩形来生成的,所以弧也是根据矩形来生成的;

public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle,

boolean useCenter, @NonNull Paint paint)

参数:

RectF oval:生成椭圆的矩形

float startAngle:弧开始的角度,以X轴正方向为0度

float sweepAngle:弧持续的角度

boolean useCenter:是否有弧的两边,True,还两边,False,只有一条弧

val paint = Paint().apply {

color = Color.RED

style = Paint.Style.STROKE//填充样式改为描边

strokeWidth = 2f//设置画笔宽度

}

val rect = RectF(20f, 10f, 600f, 300f)

canvas.drawRect(rect, paint)

paint.color = Color.GREEN

paint.strokeWidth = 5f

canvas.drawArc(rect, 0f, 90f, true, paint)

canvas.drawArc(rect, 180f, 90f, false, paint)

画笔描边效果:

image.png

画笔填充效果

FILL

路径 path

使用 canvas.drawPath(path, paint)画

直线路径

void moveTo (float x1, float y1): 表示直线的开始点;

void lineTo (float x2, float y2):直线的结束点,又是下一次绘制直线路径的开始点;lineTo()可以一直用;

void close ():将路径首尾点连接起来,形成闭环;

// 画一个三角形

val path = Path().apply {

moveTo(10f, 10f)

lineTo(10f, 100f)//第一条直线的终点,也是第二条直线的起点

lineTo(300f, 100f)//画第二条直线

close() //形成闭环

}

canvas.drawPath(path, paint)

矩形路径

void addRect (float left, float top, float right, float bottom, Path.Direction dir)

void addRect (RectF rect, Path.Direction dir)

参数其中Path.Direction有两个值:

Path.Direction.CCW:是counter-clockwise缩写,指创建逆时针方向的矩形路径;

Path.Direction.CW:是clockwise的缩写,指创建顺时针方向的矩形路径;

圆角矩形路径

void addRoundRect (RectF rect, float[] radii, Path.Direction dir)

void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)

两个画圆角函数,部分参数说明如下:

float[] radii:必须传入8个数值,分四组,分别对应每个角所使用的椭圆的横轴半径和纵轴半径,如{x1,y1,x2,y2,x3,y3,x4,y4},其中,x1,y1对应第一个角的(左上角)用来产生圆角的椭圆的横轴半径和纵轴半径,其它类推……

第二个构造函数:只能构建统一圆角大小

rx/ry:所产生圆角的椭圆的横/纵轴半径;

圆形、椭圆、弧等等

参考源博客

文字

涉及画文字相关的API比较多;

画笔设置

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

// 1.基本设置

style = Paint.Style.FILL;//绘图样式,对于设文字和几何图形都有效

textAlign = Paint.Align.CENTER;//设置文字对齐方式,取值:align.CENTER、align.LEFT或align.RIGHT

textSize = 12f;//设置文字大小

// 2.样式设置

isFakeBoldText = true // 粗体 bold

isUnderlineText = true // 下划线

textSkewX = 0.25f // 设置字体水平倾斜度

isStrikeThruText = true // 删除线

// 3.其他

textScaleX = 2f // 水平方向拉伸

}

画文字

public void drawText(String text, float x, float y, Paint paint) {

参数说明:

x : LEFT 默认,字符串的左边在屏幕的位置,CENTER 字符串的中心,RIGHT,右边

y:是指定这个字符baseline在屏幕上的位置,y不是这个字符中心在屏幕上的位置,而是baseline在屏幕上的位置

例子1:绘图样式

paint.textSize = 38f

paint.color = Color.RED

paint.strokeWidth = 2f //设置画笔宽度,必须要设置,否则设置style无效

paint.textAlign = Paint.Align.LEFT

paint.style = Paint.Style.FILL

canvas.drawText("填充(FILL) ==》Kotlin 重新学Android", 2f, 100f, paint)

paint.style = Paint.Style.STROKE

canvas.drawText("描边(STROKE) ==》Kotlin 重新学Android", 2f, 200f, paint)

paint.style = Paint.Style.FILL_AND_STROKE

canvas.drawText("填充&描边(FILL_AND_STROKE) ==》Kotlin 重新学Android", 2f, 300f, paint)

绘图样式

例子2:样式与倾斜度与水平拉伸

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

textSize = 38f

color = Color.RED

strokeWidth = 2f

textAlign = Paint.Align.LEFT

style = Paint.Style.FILL

// 样式设置

isFakeBoldText = true

isUnderlineText = true

isStrikeThruText = true

}

// ======= 水平倾斜度为:0.25,右斜

paint.textSkewX = -0.25f

canvas.drawText("textSkewX -0.25f ==> Kotlin 重新学Android", 10f, 100f, paint)

paint.textSkewX = 0.25f

canvas.drawText("textSkewX 0.25f ==> Kotlin 重新学Android", 10f, 200f, paint)

canvas.drawLine(0f, 235f, width.toFloat(), 235f, paint)

// ======= 水平拉伸

val paint2 = Paint(Paint.ANTI_ALIAS_FLAG).apply {

textSize = 38f

color = Color.RED

strokeWidth = 2f

style = Paint.Style.FILL

}

// 正常绘制

canvas.drawText("Kotlin 重新学Android", 10f, 300f, paint2)

paint2.textScaleX = 2f // 水平拉伸2倍

canvas.drawText("Kotlin 重新学Android", 10f, 400f, paint2)

// 对比

paint2.textScaleX = 1f //

canvas.drawText("Android开发艺术探索", 10f, 500f, paint2)

paint2.textScaleX = 2f

paint2.color = Color.GREEN

canvas.drawText("Android开发艺术探索", 10f, 500f, paint2)

image.png

Canvas绘图方式

普通水平方向绘制

void drawText (String text, float x, float y, Paint paint)

void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)

void drawText (String text, int start, int end, float x, float y, Paint paint)

void drawText (char[] text, int index, int count, float x, float y, Paint paint)

参考原博客

沿路径绘制

public void drawTextOnPath(String text, Path path, float hOffset,

float vOffset, Paint paint) { }

参数:

float hOffset : 与路径起始点的水平偏移距离

float vOffset : 与路径中心的垂直偏移量

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

textSize = 38f

color = Color.RED

strokeWidth = 2f

style = Paint.Style.STROKE

}

// ==== 沿路径绘制

val text = "风萧萧兮易水寒,壮士一去兮不复返"

val circlePath1 = Path().apply {

addCircle(width / 4.toFloat(), 220f, 180f, Path.Direction.CCW) // 逆時針

}

val circlePath2 = Path().apply {

addCircle(width / 4 * 3.toFloat(), 220f, 180f, Path.Direction.CCW)

}

canvas.drawPath(circlePath1, paint)

canvas.drawPath(circlePath2, paint)

paint.color = Color.GREEN

// 设置0,0 ,注意这里是逆时针画的圆

canvas.drawTextOnPath(text, circlePath1, 0f, 0f, paint)

// 设置了偏移,水平100,垂直 30f

canvas.drawTextOnPath(text, circlePath2, 100f, 30f, paint)

图片转自原博客

字体样式与设置自定义字体

参考源博客

3.区域 Region

表示的是canvas图层上的某一块封闭的区域;

构造Region

// 基本构造

public Region() //创建一个空的区域

public Region(Region region) //拷贝一个region的范围

public Region(Rect r) //创建一个矩形的区域

public Region(int left, int top, int right, int bottom) //创建一个矩形的区域

// 间接构造

public void setEmpty() //置空

public boolean set(Region region) // 替换

public boolean set(Rect r)

public boolean set(int left, int top, int right, int bottom)

// 根据路径的区域与某区域的交集,构造出新区域

public boolean setPath(Path path, Region clip)

通过Region来画一个矩形

private val region = Region(10, 10, 100, 100)

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

strokeWidth = 2f

style = Paint.Style.FILL;//绘图样式,对于设文字和几何图形都有效

color = Color.RED

}

drawRegion(canvas, region, paint)

private fun drawRegion(canvas: Canvas, rgn: Region, paint: Paint) {

val iter = RegionIterator(rgn)

val r = Rect()

while (iter.next(r)) {

canvas.drawRect(r, paint) // 画出region

}

}

使用setPath()构造不规则区域

public boolean setPath(Path path, Region clip)

参数:

path : 路径

clip:与path所构成的路径取交集,并将两交集设置为最终的区域

// 椭圆路径

val ovalPath = Path()

val rect = RectF(50f, 50f, 200f, 500f)

canvas.drawRect(rect, paint)

ovalPath.addOval(rect, Path.Direction.CCW)

// setPath时,传入一个比椭圆区域小的矩形区域,让其取【交集】

val region = Region()

region.setPath(ovalPath, Region(50, 50, 200, 300))

paint.color = Color.RED

paint.style = Paint.Style.FILL

drawRegion(canvas, region, paint)

交集效果

矩形集枚举区域——RegionIterator

一定数量的矩形所合成的形状,也可以代表区域的形状。RegionIterator类,实现了获取组成区域的矩形集的功能,RegionIterator两个函数,一个构造函数和一个获取下一个矩形的函数(next);

在Canvas中没有直接绘制Region的函数,要绘制一个区域,就只能通过利用RegionIterator构造矩形集来逼近的显示区域,就是上面的 drawRegion()方法;

根据区域构建一个矩形集,然后利用next(Rect r)来逐个获取所有矩形,绘制出来,最终得到的就是整个区域;

将上面的画笔Style从FILL改为STROKE,的效果,可以看到很多个rect绘制出来了;

STROKE region 效果

区域的合并、交叉等操作

无论是区域还是矩形,都会涉及到与另一个区域的一些操作,比如取交集、取并集等,涉及到的函数有:

// 并集

public final boolean union(Rect r)

public boolean op(Rect r, Op op) {

public boolean op(int left, int top, int right, int bottom, Op op)

public boolean op(Region region, Op op)

public boolean op(Rect rect, Region region, Op op)

// Op为

public enum Op {

DIFFERENCE(0), //最终区域为region1 与 region2不同的区域

INTERSECT(1), // 最终区域为region1 与 region2相交的区域

UNION(2), //最终区域为region1 与 region2组合一起的区域

XOR(3), //最终区域为region1 与 region2相交之外的区域

REVERSE_DIFFERENCE(4), //最终区域为region2 与 region1不同的区域

REPLACE(5); //最终区域为为region2的区域

}

实例代码:

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {

strokeWidth = 2f

color = Color.RED

style = Paint.Style.STROKE

}

val rect1 = Rect(200, 200, 400, 260)

val rect2 = Rect(270, 130, 330, 330)

canvas.let {

it.drawRect(rect1, paint)

it.drawRect(rect2, paint)

}

// 集合操作

val paint2 = Paint().apply {

style = Paint.Style.FILL

color = Color.GREEN

}

val region1 = Region(rect1)

val region2 = Region(rect2)

region1.op(region2, op) // Region.Op.INTERSECT

drawRegion(canvas, region1, paint2)

// 文字说明

paint.textAlign = Paint.Align.CENTER

paint.textSize = 28f

canvas.drawText("横为region1", 300f, 450f, paint)

canvas.drawText("竖为region2", 300f, 480f, paint)

canvas.drawText("操作为:region1.op(region2, op)", 300f, 510f, paint)

region1.op(region2,op)

图片copy自源博客

补集有点不好理解

Region其他方法

android canvas画图gc,自定义控件绘图(Canvas,Paint,Region等)篇一相关推荐

  1. html5图片上写字,Html5 canvas画图教程20:在canvas里写字

    文章写到现在才发现我忘了介绍在canvas上写字的方法,呃,这篇补上. 其实在canvas里写字是很简单的,他有两个原生方法,即strokeText(描边文字)和fillText(填充文字)--一看就 ...

  2. Android开发——图形编程(一)简单介绍与使用绘图类Paint、Canvas

    Android图形编程基础 文章目录 Android图形编程基础 画笔Paint的 画布Canvas 自定义View的基本实现方法 实例代码 绘图绘图,首先要有的就是颜色Color Android系统 ...

  3. android 画布控件,Android canvas画图操作之切割画布实现方法(clipRect)

    本文实例讲述了Android canvas画图操作之切割画布实现方法.分享给大家供大家参考,具体如下: android切割画布的历程不算很难,可是理解起来也比较麻烦,这里写一下我的理解 但是不一定正确 ...

  4. Android绘图Canvas十八般武器之Shader详解及实战篇(上)

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 前言 Android中绘图离不开的就是Canvas了,Canvas是一个庞大的知识体系,有java层的,也有jni层深入到Frame ...

  5. Android绘图Canvas十八般武器之Shader详解及实战篇(下)

    前言 上一篇<Android绘图Canvas十八般武器之Shader篇(上)> 我们知道了Bitmap的用法,及TileMode的详细情况.接下来,这一篇作为整个知识体系的下半部要讲的是S ...

  6. 【Android】自定义View、画布Canvas与画笔Paint

    安卓自定义View其实很简单.这个View可以像<[Android]利用Java代码布局,按钮添加点击事件>(点击打开链接)一样,利用Java代码生成一系列的组件.也可以配合画布Canva ...

  7. php绘图和canvas,html5 canvas画图实例用法汇总

    HTML5 canvas画图HTML5 标签用于绘制图像(通过脚本,通常是 JavaScript).不过, 元素本身并没有绘制能力(它仅仅是图形的容器) - 您必须使用脚本来完成实际的绘图任务.get ...

  8. 自定义控件之Canvas图形绘制基础练习-青春痘笑脸^_^

    对于自定义控件的意义不言而喻,所以对它的深入研究是很有必要的,前些年写过几篇关于UI效果的学习过程,但是中途比较懒一直就停滞了,而对于实际工作还是面试来说系统深入的了解自定义控件那是很有必要的,所以接 ...

  9. android绘制环形进度_Android使用Canvas绘制圆形进度条效果

    前言 Android自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制.本文从以下三个方面对Canvas绘图机制进行讲解: 画布Canvas ...

最新文章

  1. springboot + redis + 注解 + 拦截器 实现接口幂等性校验
  2. python算法与程序设计基础第二版-算法与程序设计基础(Python版) - 吴萍
  3. Cambridge career service
  4. RabbitMQ消息追踪之Firehose
  5. Java 面向对象编程的三大特性——封装、继承、多态
  6. css 图片等比例缩小_12个令人惊叹的CSS实验项目
  7. ios view 切上部分圆角_唯一可行的 iOS 架构
  8. Android项目重构之路:界面篇
  9. 安卓电视 TV端的webview网页 按键控制和一些小问题
  10. CDRX4X5X6X7X8下载安装失败的原因教程分享(CorelDRAW)
  11. python 节假日_python获取全年节假日
  12. 计算机小喇叭找不到,电脑右下角小喇叭不见了怎么办?
  13. android之设置app背景图片
  14. 如何使用语音验证码API
  15. excel双条件筛选
  16. three.js之摄像机
  17. html页面拼接,表格数据
  18. 这世上,真有人会陪你手握屠龙刀,杀得生活措手不及!
  19. 从Java程序运行的角度分析JDK1.8下JVM的内存区域划分及变量存储
  20. iCheck 的简单了解

热门文章

  1. jupyter note 打开md文件
  2. xtu oj 1375斐波纳契
  3. Macbook Air如何将m4a格式转化为mp3格式?
  4. 阿里2019社招内推!阿里云高级专家(P8)帮内推!投递简历邮箱看正文!
  5. Mysql面试题总结(1)
  6. 软件测试2022年终总结
  7. 【Python安装系统】win10系统从零开始安装Python并为不同项目设置开发环境——以安装TensorFlow2为例
  8. 力扣(202.454)补9.18
  9. 《金刚般若波罗蜜经》分段贯释
  10. JTAG和SWD定义