NO.1 基础绘制

≯℡__Kan透↙ 提交于 2020-01-28 00:21:43

NO.1 基础绘制

零蚀
🔗 HenCoder


前言

  • 获取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则为内部。外部在绘制中是不进行绘制的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mgCw2mOv-1580132929571)(media/15800957908200/15801122290368.jpg)]

  • EVEN_ODD

此参数表示交点计算后双数为外部,单数为内部。一般用于做镂空。

  • INVERSE_WINDING ,INVERSE_EVEN_ODD

与上列方法相反

  • PathMeasure
// forceClosed 强制闭合图形
PathMeasure pathMeasure = new PathMeasure(new Path(), false);
// 获取图形的长度
pathMeasure.getLength();
// 获取图形某点的正切值
pathMeasure.getPosTan();

案例分析

  • 仪表盘

案例试图如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dv6LLWrA-1580132929572)(media/15800957908200/15801268922957.jpg)]

代码内容如下:

// 生命周期在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));
}
  • 蒙版效果

正常的图片绘制:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BIfpN0HG-1580132929572)(media/15800957908200/15801302349705.jpg)]

    @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影响)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sEK72nQF-1580132929573)(media/15800957908200/15801324570829.jpg)]

 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);

    }

绘制边沿:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83yqQ0rH-1580132929573)(media/15800957908200/15801326516524.jpg)]

一开始的蒙版,是将指定区域化入一个指定图形,后来才将图片的内容在范围内绘制,所以可以西安指定一个范围,再在范围中国呢指定蒙版的区域。

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);

🔗 前言
🔗 Android 自定义控件列表

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!