自定义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{ |