NO.1 基础绘制
前言
- 获取dp所对应的xp数值
public static float dp2px(int dp){
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp, Resources.getSystem().getDisplayMetrics());
}
- 旋转方向
Path.Direction.CW; //顺时针 /** clockwise */
Path.Direction.CCW; // 逆时针/** counter-clockwise */
一般在我们绘制drawRect和drawCircle时候都需要填写回执方向的参数,次方向参数的主要作用,是用于图形的交叉绘制。与它息息相关的绘制方法是path.setFilltype(Path.FillType.EVEN),FillType有以下几个枚举参数:
WINDING (0), // 默认
/**
* Specifies that "inside" is computed by an odd number of edge
* crossings.
*/
EVEN_ODD (1),
/**
* Same as {@link #WINDING}, but draws outside of the path, rather than inside.
*/
INVERSE_WINDING (2),
/**
* Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
*/
INVERSE_EVEN_ODD(3);
- WINDING
当我们判断一个区域是否在图形的内部时候,会用到以下判断方式,在区域内任意做一条射线,射线与图形边沿存在交点(非切点),若方向相同焦点数相加,方向相反,交点数相减,如果result为0,则是在外部,若不为0则为内部。外部在绘制中是不进行绘制的。
- EVEN_ODD
此参数表示交点计算后双数为外部,单数为内部。一般用于做镂空。
- INVERSE_WINDING ,INVERSE_EVEN_ODD
与上列方法相反
- PathMeasure
// forceClosed 强制闭合图形
PathMeasure pathMeasure = new PathMeasure(new Path(), false);
// 获取图形的长度
pathMeasure.getLength();
// 获取图形某点的正切值
pathMeasure.getPosTan();
案例分析
- 仪表盘
案例试图如下
代码内容如下:
// 生命周期在super之后
{
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
pathArc.addArc(-RADIUS, -RADIUS, RADIUS, RADIUS, 150, 240);
// 通过pathArc获取到线段长度
PathMeasure measure = new PathMeasure(pathArc, false);
// 长度要减去最后一个刻度,不然无法显示
float arc_length = measure.getLength() - Utils.dp2px(2);
// 绘制虚线的形状,是以Android的坐标系为准,安装图形的切点绘制
pathDash.addRect(0, 0, Utils.dp2px(2), Utils.dp2px(10), Path.Direction.CW);
// advance:虚线间距 phase:起始点的距离
effect = new PathDashPathEffect(pathDash, arc_length / 19, 0, PathDashPathEffect.Style.ROTATE);
}
draw的主要的内容:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc((float) getWidth() / 2 - RADIUS,
(float) getWidth() / 2 - RADIUS,
(float) getWidth() / 2 + RADIUS,
(float) getWidth() / 2 + RADIUS,
150,
240,
false,
paint);
/**
* 刻度盘的样式
*/
paint.setPathEffect(effect);
// 绘制DashPathEffect的paint的样式
canvas.drawArc((float) getWidth() / 2 - RADIUS,
(float) getWidth() / 2 - RADIUS,
(float) getWidth() / 2 + RADIUS,
(float) getWidth() / 2 + RADIUS,
150,
240,
false,
paint);
paint.setPathEffect(null);
int key = 4;
canvas.drawLine(getWidth() / 2, getWidth() / 2,
(float) getWidth() / 2 + (float) Math.cos(Math.PI / 6 * 5 + Math.PI / 3*4 / 19 * key) * point_length,
(float) getWidth() / 2 + (float) Math.sin(Math.PI / 6 * 5 + Math.PI / 3*4 / 19 * key) * point_length, paint);
Log.e("tag", "onDraw: " + ((float) Math.sin(Math.PI / 3 * 2 + Math.PI / 30 * key) * point_length));
}
- 蒙版效果
正常的图片绘制:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(getBitmap(width),Utils.dp2px(50),Utils.dp2px(50),paint);
}
public Bitmap getBitmap(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
// 只能取到宽高,知道宽高比,进行设置,这样可以节约性能
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
options.inJustDecodeBounds = false;
options.inDensity = options.outWidth;
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
}
指定绘制的图片区域:
⚠️在绘制过程中,我们会在draw中设置蒙版canvasDraw,以此来指定绘制的区域,但是并不能达到效果,主要是因为在蒙版之下还有一个底层的canvas,系统将其当作蒙版的区域,导致canvas上所有的的区域都会被显示。所以在此需要用到离屏缓冲(离屏缓冲是用来高速绘制静态图的),将图形多次绘制进行合成(将绘制的部分拿出来,和整体的canvas脱离,这样蒙版就不会受整体的canvas影响)。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 离屏缓冲,拿到Bitmap区域
int saved=canvas.saveLayer(rectF,paint);
// 绘制指定区域(蒙版区域)
canvas.drawOval(PADDING/2*3,PADDING/2*3,(PADDING+width)/3*2,(PADDING+width)/3*2,paint);
paint.setXfermode(xfermode);
canvas.drawBitmap(getBitmap(width),PADDING,PADDING,paint);
paint.setXfermode(null);
// 离屏缓冲放回原处
canvas.restoreToCount(saved);
}
public Bitmap getBitmap(int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
// 只能取到宽高,知道宽高比,进行设置,这样可以节约性能
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
options.inJustDecodeBounds = false;
options.inDensity = options.outWidth;
options.inTargetDensity = width;
return BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
}
绘制边沿:
一开始的蒙版,是将指定区域化入一个指定图形,后来才将图片的内容在范围内绘制,所以可以西安指定一个范围,再在范围中国呢指定蒙版的区域。
canvas.drawOval( PADDING/2*3,PADDING/2*3,(PADDING+width)/3*2,(PADDING+width)/3*2,paint);
// 离屏缓冲,拿到Bitmap区域
int saved=canvas.saveLayer(rectF,paint);
// 绘制指定区域(蒙版区域)
canvas.drawOval(PADDING/2*3+10,PADDING/2*3+10,(PADDING+width)/3*2-10,(PADDING+width)/3*2-10,paint);
paint.setXfermode(xfermode);
canvas.drawBitmap(getBitmap(width),PADDING,PADDING,paint);
paint.setXfermode(null);
// 离屏缓冲放回原处
canvas.restoreToCount(saved);
来源:CSDN
作者:零蚀zero eclipse
链接:https://blog.csdn.net/qq_38315348/article/details/104095932