• Android Canvas之Path操作


    接上篇,Android自己定义View工具:Paint&Canvas(二)

    上一篇中介绍的Canvas绘制图形仅仅能画一些常规图形(圆。椭圆。矩形等),假设想绘制更复杂的图形。Path神器来了!

    Path是什么?
    Path类将多种复合路径(多个轮廓,如直线段、二次曲线、立方曲线)封装在其内部的几何路径。

    怎样绘制Path:
    通过设置Paint的Style(FILL、STROKE、FILL_AND_STROKE),然后调用canvas.drawPath(path, paint)。Path还能够用于剪切或者在路径上绘制文本(canvas.drawTextOnPath())。

    Path有两个构造函数:

    Path() // 空的构造函数
    Path(Path src) //创建一个新的路径。而且从src路径里赋值内容

    Path经常用法一览表:

    Path经常用法 备注
    线操作  
    lineTo、rLineTo 绘制线
    点操作  
    moveTo、rMoveTo 改变后面操作的起始点位置
    setLastPoint 改变前面操作中最后点的位置
    加入常规图形  
    addRect 绘制矩形
    addRoundRect 绘制圆角矩形
    addCircle 绘制圆
    addOval 绘制椭圆
    addArc、arcTo 绘制圆弧
    闭合path  
    close 假设连接Path起点和终点能形成一个闭合图形,则会将起点和终点连接起来形成一个闭合图形
    贝塞尔曲线  
    quadTo、rQuadTo、cubicTo、rCubicTo 贝塞尔曲线
    • 线操作
    lineTo(float x, float y) //加入当前点到目标点(x,y)构成的直线到path
    rLineTo(float dx, float dy) //基于当前坐标系,即以path最后的那个点
    //为坐标系原点(0,0),假设前面没有path的点,默认是屏幕左上角(0,0).

    注:lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点(0,0)!
    演示样例:

    //设置Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10f);
    //设置Path
    Path path = new Path();
    //屏幕左上角(0,0)到(200,400)画一条直线
    path.lineTo(200, 400);
    //(200, 400)到(400,600)画一条直线
    path.lineTo(400, 600);
    //以(400,600)为起始点(0,0)偏移量为(400,600)画一条直线。
    //其终点坐标实际在屏幕的位置为(800,1200)
    path.rLineTo(400, 600);
    canvas.drawPath(path, mPaint);

    效果图:

                                                      


    • 点操作
    moveTo(float x, float y) //改变接下来操作的起点位置为(x,y)
    rMoveTo(float dx, float dy) //接下来要操作的起点位置为(x+dx,y+dy)
    setLastPoint(float dx, float dy) //改变前一步操作点的位置。会改变前一步的操作

    先来看moveTo和rMoveTo的差别。演示样例:

    //初始化Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10f);
    //初始化Path
    Path path = new Path();
    //将坐标系原点从(0,0)移动到(100,100)
    path.moveTo(100, 100);
    //画从(100,100)到(400,400)之间的直线
    path.lineTo(400, 400);
    //path.rMoveTo(0, 100); //临时凝视
    path.lineTo(400, 800);
    canvas.drawPath(path, mPaint);

    效果图:

                                                                           

    上面代码中,打开凝视的path.rMoveTo(0, 100)。意为下一步操作起点位置由(400,400)变为(400+0,400+100)即为(400,500),效果图:

                                                   


    接下来看下,moveTo和setLastPoint的差别。相同用上面的代码,加上path.setLastPoint(100, 800)。例如以下:

    //初始化Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10f);
    //初始化Path
    Path path = new Path();
    //将坐标系原点从(0,0)移动到(100,100)
    path.moveTo(100, 100);
    //画从(100,100)到(400,400)之间的直线
    path.lineTo(400, 400);
    //新加的setLastPoint
    path.setLastPoint(100, 800);
    path.lineTo(400, 800);
    canvas.drawPath(path, mPaint);

    效果图:

                                                  


    虚线本来是没设置setLastPoint之前的路径,设置setLastPoint(100,800)后。影响到了前一步lineTo(400,400)操作,变成了lineTo(100,800),最后结果就变成了红颜色的path路径,能够得出结论:moveTo影响的是后面操作的起点位置。不会影响之前的操作;而 setLastPoint改变前一步操作最后一个点的位置,不仅影响前一步操作,同一时候也会影响后一步操作!

    • 绘制常规图形
    //绘制圆
    addCircle(float x, float y, float radius, Direction dir) 
     //绘制椭圆
    addOval(RectF oval, Direction dir)
    addOval(float left, float top, float right, float bottom, Direction dir) 
    //绘制矩形
    addRect(RectF rect, Direction dir) 
    addRect(float left, float top, float right, float bottom, Direction dir) 
    //绘制圆角矩形
    addRoundRect(RectF rect, float rx, float ry, Direction dir) 
    addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)
    addRoundRect(RectF rect, float[] radii, Direction dir)
    addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)

    全部方法里面都有一个共同的參数Direction :

    Direction 备注
    Path.Direction.CCW counter-clockwise ,沿逆时针方向绘制
    Path.Direction.CW clockwise 。沿顺时针方向绘制

    Direction 使用方法演示样例:

    //初始化Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(2f);
    paint.setTextSize(40f);
    //初始化Path
    Path path = new Path();
    //以(600,600)为圆心。300为半径绘制圆 
    //Path.Direction.CW顺时针绘制圆 Path.Direction.CCW逆时针绘制圆
    path.addCircle(600, 600, 300, Path.Direction.CW);
    //沿path绘制文字
    canvas.drawTextOnPath("痛苦最好是别人的。快乐才是自己的。麻烦将是临时的,朋友总是永恒的。", path, 0, 0, paint);
    canvas.drawPath(path, paint);

    效果图:

                                                  


    效果非常明显,设置为Path.Direction.CW时,文字沿顺时针绘制;设置为Path.Direction.CCW时。文字沿逆时针绘制。

    绘制常规图形演示样例:

    //初始化Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10f);
    Path path = new Path();
    //以(400,200)为圆心,半径为100绘制圆
    path.addCircle(400, 200, 100, Path.Direction.CW);
    
    //绘制椭圆
    RectF rectF = new RectF(100, 350, 500, 600);
    //第一种方法绘制椭圆
    path.addOval(rectF, Path.Direction.CW);
    //另外一种方法绘制椭圆
    path.addOval(600, 350, 1000, 600, Path.Direction.CW);
    
    //绘制矩形
    RectF rect = new RectF(100, 650, 500, 900);
    //第一种方法绘制矩形
    path.addRect(rect, Path.Direction.CW);
    //第一种方法绘制矩形
    path.addRect(600, 650, 1000, 900, Path.Direction.CCW);
    
    //绘制圆角矩形
    RectF roundRect = new RectF(100, 950, 300, 1100);
    //第一种方法绘制圆角矩形
    path.addRoundRect(roundRect, 20, 20, Path.Direction.CW);
    //另外一种方法绘制圆角矩形
    path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW);
    //第三种方法绘制圆角矩形 
    //float[] radii中有8个值,依次为左上角,右上角,右下角,左下角的rx,ry
    RectF roundRectT = new RectF(600, 950, 800, 1100);
    path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW);
    //第四种方法绘制圆角矩形
    path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW);
    canvas.drawPath(path, paint);

    效果图:

                                                             


    绘制圆弧:

     

    //绘制圆弧
    addArc(RectF oval, float startAngle, float sweepAngle)
    addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)
    
    //forceMoveTo:是否强制将path最后一个点移动到圆弧起点,
    //true是强制移动。即为不连接两个点。false则连接两个点
    arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
    arcTo(RectF oval, float startAngle, float sweepAngle)
    arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

    addArc和arcTo都是加入圆弧到path中,只是他们之间还是有差别的:addArc是直接加入圆弧到path中。而arcTo会推断要绘制圆弧的起点与绘制圆弧之前path中最后的点是否是同一个点,假设不是同一个点的话,就会连接两个点。


    演示样例:

    //在(400, 200, 600, 400)区域内绘制一个300度的圆弧
    RectF rectF = new RectF(400, 200, 600, 400);
    path.addArc(rectF, 0, 300);
    //在(400, 600, 600, 800)区域内绘制一个90度的圆弧。而且不连接两个点
    RectF rectFTo = new RectF(400, 600, 600, 800);
    path.arcTo(rectFTo, 0, 90, true);
    //等价于path.addArc(rectFTo, 0, 90);
    canvas.drawPath(path, paint);

    效果图:

                                                     


    改动一下代码:

     

    //在(400, 200, 600, 400)区域内绘制一个300度的圆弧
    RectF rectF = new RectF(400, 200, 600, 400);
    path.addArc(rectF, 0, 300);
    //在(400, 600, 600, 800)区域内绘制一个90度的圆弧。而且连接两个点
    RectF rectFTo = new RectF(400, 600, 600, 800);
    path.arcTo(rectFTo, 0, 90,false);
    //等价于path.arcTo(rectFTo, 0, 90);
    canvas.drawPath(path, paint);

    对照发现我们仅仅是将arcTo最后一个參数变成了false。即连接绘制圆弧之前path的最后一个点和绘制圆弧的起点。效果图:



    • 闭合path
    path.close();

    假设path的终点和起始点不是同一个点的话,close()连接这两个点,形成一个封闭的图形,演示样例:

    //初始化Paint
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10f);
    //初始化Path
    Path path = new Path();
    //将坐标原点移动到(300,300,)
    path.moveTo(300, 300);
    //连接(300, 300)和(300, 600)成一条线
    path.lineTo(300, 600);
    //连接(300, 600)和(600, 600)成一条线
    path.lineTo(600, 600);
    //path.close();临时凝视
    canvas.drawPath(path, paint);

    效果图:

                                                         


    改动一下代码。将上面的path.close()打开,效果图:

                                                         


    能够调用close()后,连接了path的起始点和终点形成了一个封闭图形!

    贝塞尔曲线内容较多,放在下一篇了!


  • 相关阅读:
    在C#程序中模拟发送键盘按键消息
    C# UDPCLIENT多线程实例
    【转】WINFORM下FTP客户端的实现
    抓取屏幕或窗体并保存成图片
    c# 判断窗体已打开则显示为焦点
    【转】C#中dataGridView用法实例分析
    【转】VC6控件小记
    .Net部署二三事之一——如何为VS安装文件MSI制作更新补丁MSP
    [转]C#串口serialPort操作
    VS向IIS发布C#或VB应用程序
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7388340.html
Copyright © 2020-2023  润新知