自定义View
Canvas.drawXXX() 和 Paint 基础
Canvas.drawColor(@ColorInt int color)颜色填充
这是最基本的drawXXX()方法:在整个绘制区域涂上指定的颜色。
canvas.drawColor(Color.BLACK) //纯黑 |
类似的方法还有drawRGB(int r, int g, int b) 和 drawARGB(int a, int r, in g, int b),它们和drawColor(color)只是使用方式不同,作用都是一样的。
canvas.drawRGB(100, 200, 100); |
drawCircle(float centerX, float centerY, float radius, Paint paint) 画圆
前两个参数centerX、centerY是圆心的坐标,第三个参数radius是圆的半径,单位都是像素
canvas.drawCircle(300f, 300f, 200f, paint); |
插播一: Paint.setColor(int color)
例如,你要画一个红色的圆,并不是写成 canvas.drawCircle(300, 300, 200, RED, paint) 这样,而是像下面这样:
paint.color = Color.RED |
插播二: Paint.setStyle(Paint.Style style)
paint.style = Paint.Style.STROKE |
setStyle(Style style) 这个方法设置的是绘制的 Style 。Style 具体来说有三种: FILL, STROKE 和 FILL_AND_STROKE 。FILL 是填充模式,STROKE 是画线模式(即勾边模式),FILL_AND_STROKE 是两种模式一并使用:既画线又填充。它的默认值是 FILL,填充模式。
插播三: Paint.setStrokeWidth(float width)
在 STROKE 和 FILL_AND_STROKE 下,还可以使用 paint.setStrokeWidth(float width) 来设置线条的宽度:
paint.style = Paint.Style.STROKE |
插播四: 抗锯齿
在绘制的时候,往往需要开启抗锯齿来让图形和文字的边缘更加平滑。开启抗锯齿很简单,只要在 new Paint() 的时候加上一个 ANTI_ALIAS_FLAG 参数就行:
private val paint = Paint(Paint.ANTI_ALIAS_FLAG) |
另外,你也可以使用paint.isAntiAlias = true来动态开关抗锯齿。
drawRect(float left, float top, float right, float bottom, Paint paint)
left, top, right, bottom 是矩形四条边的坐标。
paint.style = Paint.Style.FILL |
drawPoint(float x, float y, Paint paint) 画点
x 和 y 是点的坐标。点的大小可以通过 paint.setStrokeWidth(width) 来设置;点的形状可以通过 paint.setStrokeCap(cap) 来设置:ROUND 画出来是圆形的点,SQUARE 或 BUTT 画出来是方形的点。
paint.strokeWidth = 20f |
drawPoints(float[] pts, int offset, int count, Paint paint) / drawPoints(float[] pts, Paint paint) 画点(批量)
同样是画点,它和 drawPoint() 的区别是可以画多个点。pts 这个数组是点的坐标,每两个成一对;offset 表示跳过数组的前几个数再开始记坐标;count 表示一共要绘制几个点。
val points = floatArrayOf(0f, 0f, 50f, 50f, 50f, 100f, 100f, 50f, 100f, 100f, 150f, 50f, 150f, 100f) |
drawOval(float left, float top, float right, float bottom, Paint paint) 画椭圆
只能绘制横着的或者竖着的椭圆,不能绘制斜的(斜的倒是也可以,但不是直接使用 drawOval(),而是配合几何变换,后面会讲到)。left, top, right, bottom 是这个椭圆的左、上、右、下四个边界点的坐标。
paint.style = Paint.Style.FILL |
drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 画线
startX, startY, stopX, stopY 分别是线的起点和终点坐标。
canvas.drawLine(200f,200f,800f,500f,paint) |
由于直线不是封闭图形,所以 setStyle(style) 对直线没有影响。
drawLines(float[] pts, int offset, int count, Paint paint) / drawLines(float[] pts, Paint paint) 画线(批量)
val points = floatArrayOf(20f, 20f, 120f, 20f, 70f, 20f, 70f, 120f, 20f, 120f, 120f, 120f, 150f, 20f, 250f, 20f, 150f, 20f, 150f, 120f, 250f, 20f, 250f, 120f, 150f, 120f, 250f, 120f) |
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint) 画圆角矩形
left, top, right, bottom 是四条边的坐标,rx 和 ry 是圆角的横向半径和纵向半径。
canvas.drawRoundRect(100f,100f,500f,300f,50f,50f,paint) |
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) 绘制弧形或扇形
drawArc() 是使用一个椭圆来描述弧形的。left, top, right, bottom 描述的是这个弧形所在的椭圆;startAngle 是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度),sweepAngle 是弧形划过的角度;useCenter 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。
paint.style = Paint.Style.FILL |
drawPath(Path path, Paint paint) 画自定义图形
drawPath(path) 这个方法是通过描述路径的方式来绘制图形的,它的 path 参数就是用来描述图形路径的对象。path 的类型是 Path ,使用方法大概像下面这样:
path.addArc(200f, 200f, 400f, 400f, -225f, 225f) |
Path 方法第一类:直接描述路径
这一类方法还可以细分为两组:添加子图形和画线(直线或曲线)
第一组: addXxx() ——添加子图形
addCircle(float x, float y, float radius, Direction dir) 添加圆
x, y, radius 这三个参数是圆的基本信息,最后一个参数 dir 是画圆的路径的方向。顺时针CW(clockwise),逆时针(CCW counter-clockwise)。
第二组:xxxTo() ——画线(直线或曲线)
这一组和第一组 addXxx() 方法的区别在于,第一组是添加的完整封闭图形(除了 addPath() ),而这一组添加的只是一条线
lineTo(float x, float y) / rLineTo(float x, float y) 画直线
从当前位置向目标位置画一条直线, x 和 y 是目标位置的坐标。这两个方法的区别是,lineTo(x, y) 的参数是绝对坐标,而 rLineTo(x, y) 的参数是相对当前位置的相对坐标 (前缀 r 指的就是 relatively 「相对地」)。
patin.style = Paint.Style.STROKE |
通过 moveTo(x, y) 或 rMoveTo() 来改变当前位置,从而间接地设置这些方法的起点。
另外,第二组还有两个特殊的方法: arcTo() 和 addArc()。它们也是用来画线的,但并不使用当前位置作为弧线的起点。
arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo) / arcTo(RectF oval, float startAngle, float sweepAngle) 画弧形
这个方法和 Canvas.drawArc() 比起来,少了一个参数 useCenter,而多了一个参数 forceMoveTo 。
少了 useCenter ,是因为 arcTo() 只用来画弧形而不画扇形,所以不再需要 useCenter 参数;而多出来的这个 forceMoveTo 参数的意思是,绘制是要「抬一下笔移动过去」,还是「直接拖着笔过去」,区别在于是否留下移动的痕迹。
paint.style = Paint.Style.STROKE |
paint.style = Paint.Style.STROKE |
addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle) / addArc(RectF oval, float startAngle, float sweepAngle)
又是一个弧形的方法。一个叫 arcTo ,一个叫 addArc(),都是弧形,区别在哪里?其实很简单: addArc() 只是一个直接使用了 forceMoveTo = true 的简化版 arcTo() 。
paint.style = Paint.Style.STROKE |
close() 封闭当前子图形
它的作用是把当前的子图形封闭,即由当前位置向当前子图形的起点绘制一条直线。
paint.style = Paint.Style.STROKE |
close() 和 lineTo(起点坐标) 是完全等价的。
另外,不是所有的子图形都需要使用 close() 来封闭。当需要填充图形时(即 Paint.Style 为 FILL 或 FILL_AND_STROKE),Path 会自动封闭子图形。
以上就是 Path 的第一类方法:直接描述路径的。
drawBitmap(Bitmap bitmap, float left, float top, Paint paint) 画 Bitmap
绘制 Bitmap 对象,也就是把这个 Bitmap 中的像素内容贴过来。其中 left 和 top 是要把 bitmap 绘制到的位置坐标。它的使用非常简单。
drawBitmap(bitmap, 200, 100, paint); |
drawText(String text, float x, float y, Paint paint) 绘制文字
canvas.drawText(text, 200, 100, paint); |
插播五: Paint.setTextSize(float textSize)
val text = "Hello HenCoder" |
练习,画一个饼图
class PracticePieChartView: View{ |
