首页 > 其他分享 >Android开发 - Canvas中Path路径的详解与使用

Android开发 - Canvas中Path路径的详解与使用

时间:2024-07-25 22:07:33浏览次数:8  
标签:Canvas RectF 坐标 path Path Android 100 500

Path回顾

  • Path类封装复合(多轮廓)几何路径由直线段二次曲线三次曲线组成。它可以用画布绘制:canvas.drawPath(path, paint)填充或笔划(基于绘画的样式),或者可以用于剪裁或绘制路径上的文本Path既是路径,路径走多了就变成一种套路,只要我们会解套,那这种套路就是高速公路。路径走完形成闭环,最终形成一个图形

paint回顾

  • path的合作伙伴是Paintpath设置好路径而绘制由paint完成绘制,paint既是画笔以下是基本的画笔设置

    paint.setAntiAlias(true);
    // 设置画笔的风格style (Paint.Style.FILL填充,Paint.Style.STROKE描边    Paint.Style.FILL_AND_STROKE填充加描边)
    paint.setStyle(Paint.Style.STROKE);
    // 设置画笔的颜色
    paint.setColor(Color.RED);
    //设置描边宽度
    paint.setStrokeWidth(10f);
    

    关于setStyle注意点

    1. 不同的填充效果不一样,比如绘制路径,三个点描边出来的效果却是两条线,而填充模式下是一个三角形的色块

      • paint.setStyle(Paint.Style.STROKE);

      • paint.setStyle(Paint.Style.FILL);

    2. Paint.Style.FILL_AND_STROKE;:会出现角有缺陷,在使用需要注意

Path的使用

构造path对象

构造空对象

public void path()

拷贝一个对象

public void path(Path src)

Path的方法

改变起始坐标:moveTo

  • moveTo(x,y);

    • 参数解析
      • x:设置新的x轴坐标,默认为0
      • y:设置新的y轴坐标,默认为0
  • path默认的起始坐标是0,0;如果想改变起始坐标位置,通过moveTo来设置

    private void moveTo(Path path) {
        path.moveTo(x, y);
        path.lineTo(0, 1000);
        path.lineTo(500, 500);
    }
    
    

  • 图一是没设置moveTo(0,0)默认(0,0)坐标图二moveTo(100,100)新的坐标点,起始点为A,因此只变更A的位置

画点成线:rLineTo、lineTo

  • rLineTo(x,y);

    • 参数解析
      • x如果没有上一个连接点,则从0开始计算放置新的x轴坐标连接点;否则从上一个(y点)连接点开始计算放置新的x轴坐标连接点
      • y以上一个连接点(x点)为起点计算放置新的y轴坐标连接点
  • lineTo(x,y);

    • 参数解析
      • x从0开始放置新的x轴坐标连接点
      • y从0开始放置新的y轴坐标连接点
  • lineTo相同,但坐标被视为相对于最后一个此轮廓上的点。如果没有上一个点,则将moveTo(0,0)将自动插入

  • rLineTolineTo的区别:

    • rLineTo:从A点B点C点的坐标以B点为起点,也就是后一个点以前一个坐标为起点

      private void rLineTo(Path path) {
          path.rLineTo(0, 1000);	//A(x):0; B(y):1000
          path.rLineTo(1000, 0);	//c(x):1000; y:0
      }
      

    • lineTo起点为0,直接将ABC三个点按顺序在view中连起来

      private void lineTo(Path path) {
          path.lineTo(0, 1000);	//A(x):0; B(y):1000
          path.lineTo(1000, 0);	//c(x):1000; y:0
      }
      

贝塞尔曲线:quadTo

  • quadTo(float x1, float y1, float x2, float y2);

    • 参数解析
      • x1:决定曲线弯曲朝向
      • y1:决定曲线弯曲高度
      • x2:决定起始点的横向位置
      • y2:决定起始点的纵向位置
  • 注意事项:在quadTo方法调用时moveTo方法也会进行调整:

    • moveTo(x, y)调整后参数解析
      • x:决定终点的横向位置
      • y:决定终点的纵向位置
  • 代码解析

     private void quadTo(Path path) {
        path.moveTo(100, 0);	//决定终点位置
        path.quadTo(100, 1000, 1000, 0);	//决定弯曲朝向、弯曲高度、终点位置
    }
    

贝塞尔曲线:rQuadTo

  • quadTo基本相同,改变的有moveTo方法决定终点位置变为决定起始点位置,而rQuadTo方法决定起始点的位置则变为决定终点位置;和决定弯曲朝向与决定弯曲高度的参数对比值变化。如果多画一个曲线,那么第二个rQuadTo画出来的曲线起始点将连接上一个曲线的终点。如果没有上一个点,则将moveTo(0, 0)将自动插入。

立方贝塞尔:cubicTo

  • cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

    • 参数解析
      • x1:决定曲线的弯曲朝向
      • y1:决定曲线的弯曲高度
      • x2:决定曲线的弯曲朝向
      • y2:决定曲线的弯曲高度
      • x3:决定终点的横向位置
      • y3:决定终点的纵向位置
  • 代码实例

    private void cubicTo(Path path) {
    
        int width=getWindowSize(0)/2;
        int height=getWindowSize(1)/2;
    
        path.cubicTo(0, height, width, height, width, 0);
    }
    

圆弧:arcTo

  • arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

    • 参数解析
      • oval:调用RectF决定扇形图形view大小
      • startAngle:开始角度
      • sweepAngle:扇形角度
      • forceMoveTo:如果为true,则始终以圆弧开始新轮廓
  • 代码实例

    private void arcTo(Path path) {
        paint.setStyle(Paint.Style.FILL);
        RectF rectF=new RectF(0,0,500,500);
        path.arcTo(rectF,startAngle,sweepAngle,true);
    
    }
    

关闭当前轮廓 :close

  • close():关闭当前轮廓。如果当前点不等于轮廓的第一个点,自动添加线段与第一个点连接。

  • 没有调用close()之前三个点确定两条线

    private void close(Path path) {
        path.moveTo(100,100);
        path.lineTo(100,500);
        path.lineTo(500,500);
    }
    

  • 调用close()三个点首尾相连

    private void close(Path path) {
        path.moveTo(100,100);
        path.lineTo(100,500);
        path.lineTo(500,500);
        path.close();
    }
    

将闭合矩形轮廓添加到路径:addRect

  • addRect(RectF rect, Direction dir)

    • 参数解析
      • rect:调用RectF对象确定矩形区域
      • dir:绘制矩形轮廓的方向Path.DirectionCW顺时针Path.Direction.CCW逆时针
  • 代码实例

    private void addRect(Path path)
    {
        RectF rect=new RectF(0,0,500,500);
        path.addRect(rect, Path.Direction.CCW);
    
    }
    

绘制椭圆:addOval

  • addOval(RectF oval, Direction dir)

    • 参数解析:
      • oval:调用RectF对象确定椭圆区域
      • dir:绘制椭圆轮廓的方向Path.DirectionCW顺时针Path.Direction.CCW逆时针
  • 代码实例

    private void addOval(Path path) {
        RectF rect = new RectF(0, 0, 1000, 500);	//如果后2个参数相等绘制出来的图形就是圆形
        path.addOval(rect, Path.Direction.CCW);
    }
    

绘制圆形:addCircle

  • addCircle(float x, float y, float radius, Direction dir)

    • 参数解析
      • x:圆心的x轴坐标位置
      • y:圆心的y轴坐标位置
      • radius:半径
      • dir:绘制圆形轮廓的方向Path.DirectionCW顺时针Path.Direction.CCW逆时针
  • 代码实例

    private void addCircle(Path path) {
        path.addCircle(100, 100, 100, Path.Direction.CCW);
    }
    

在矩形区域画弧度:addArc

  • addArc(RectF oval, float startAngle, float sweepAngle)

    • 参数解析
      • oval:调用RectF对象确定圆弧区域
      • startAngle:开始角度
      • sweepAngle:扇形角度
  • 代码实例

    private void addArc(Path path) {
        paint.setStyle(Paint.Style.STROKE);	//设置画笔空心
        RectF rect = new RectF(0, 0, 500, 500);	//如果这个矩形是一个正方形,那么画出来的弧度是半圆形,否则是一个不规则的股弧度(1000,500就是压扁发半圆,500,1000就是瘦高的半圆)
        path.addArc(rect,0,180);
    }
    

    private void addArc(Path path) {
        paint.setStyle(Paint.Style.FILL);	//设置画笔实心
        RectF rect = new RectF(0, 0, 500, 500);
        path.addArc(rect,0,180);
    }
    

在矩形中绘制一个圆形/圆角矩形:addRoundRect

  • addRoundRect(RectF rect, float rx, float ry, Direction dir)

    • 参数解析
      • rect:调用RectF对象确定矩形区域
      • rx:决定圆角角度的x轴坐标位置
      • ry:决定圆角角度的y轴坐标位置
      • dir:绘制圆形轮廓的方向Path.DirectionCW顺时针Path.Direction.CCW逆时针
  • 代码实例

    private void addRoundRect(Path path) {
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addRoundRect(rect,rect.right/2,rect.bottom/2, Path.Direction.CW);
    }
    

    private void addRoundRect(Path path) {
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addRoundRect(rect,100,100, Path.Direction.CW);
    }
    

  • 注意点

    • rx或者ry只要有一个角的坐标为0都无法生效
    • rx和ry其实可以看成各个顶点的角度百分比

在路径中添加新的路径(子路径):addPath

三种方式

  1. addPath(Path src, Matrix matrix)
  2. addPath(Path src)
  3. addPath(Path src, float dx, float dy)

参数解析

  • src:可以将已存在的path路径进行拷贝

  • matrix:指定子路径在父路径中的坐标位置,通常需要先实例化matrix后进行matrix.setTranslate(x, y);设置好坐标后进行传入。如果没有,默认覆盖在父路径的view上

  • dx:指定子路径在父路径中的x轴坐标位置。如果没有,默认覆盖在父路径view的x轴坐标上

  • dy:指定子路径在父路径中的y轴坐标位置。如果没有,默认覆盖在父路径view的y轴坐标上

代码实例

private void addPath(Path path) {
    RectF rect = new RectF(0, 0, 1000, 500);
    path.addRoundRect(rect,0,0, Path.Direction.CW);

    Path path1=new Path(path);
    Matrix matrix=new Matrix();
    matrix.setTranslate(200,200);

    path.addPath(path1,100,100);
    path.addPath(path1,matrix);
}

整体偏移 :offset

  • offset(x, y)

    • 参数解析
      • x:需要偏移到的x轴坐标位置
      • y:需要偏移到的y轴坐标位置
  • offset是针对整个path来完成偏移的,而不是某个点,与MoveTo不同MoveTo是针对起始坐标点

  • 起始坐标是(0,0),通过偏移来完成整体的下移

    private void offset(Path path) {
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addRoundRect(rect,0,0, Path.Direction.CW);
    
        path.offset(100,100);
    }
    

重置最后一个点的位置:setLastPoint

  • setLastPoint(x, y)

    • 参数解析
      • x:设置最后一个点的x轴坐标位置
      • y:设置最后一个点的y轴坐标位置
  • 代码实例

    • 正常如下

      private void setLastPoint(Path path) {
          path.lineTo(0,1000);
          path.lineTo(500,1000);
      //  path.setLastPoint(500,500);
      }
      

    • setLastPoint

      private void setLastPoint(Path path) {
          path.setLastPoint(500,500);
      }
      

路径坐标控制:transform

  • transform(x, y)

    • 参数解析
      • x:设置x轴坐标位置
      • y:设置y轴坐标位置
  • 通过Matrix对path的路径进行控制和操控,比offset更灵活,只要操作Matrix即可完成当前path的变种

    Matrix matrix = new Matrix();
    matrix.setTranslate(0, 0);
    path.transform(matrix);
    canvas.drawPath(path, paint);
    

双路径区域处理:OP

  • path的op()方法是把自身和另外一条path中的区域做相应的处理

  • 代码实例

    Path path1 = new Path();
    path1.addCircle(150, 150, 100, Path.Direction.CW);
    
    Path path2 = new Path();
    path2.addCircle(200, 200, 100, Path.Direction.CW);
    
    path1.op(path2, Path.Op.DIFFERENCE);	//OP处理
    canvas.drawPath(path1, mPaint);
    
  • 传入参数有5种模式

    • DIFFERENCE:减去Path2Path1区域剩下的部分

    • INTERSECT:保留Path2Path1共同的部分

    • UNION:保留Path1Path2

    • XOR:保留Path1Path2去除共同的部分

    • REVERSE_DIFFERENCE :减去Path1Path2区域剩下的部分

计算边界:computeBounds

  • computeBounds (RectF bounds, boolean exact)

    • bounds:调用RectF对象创建一个矩形区域,测量结果会放入这个矩形
    • exact是否精确测量,目前这一个参数作用已经废弃,一般写true即可
  • 代码实例

    // 移动canvas,mViewWidth与mViewHeight在 onSizeChanged 方法中获得
    canvas.translate(mViewWidth/2,mViewHeight/2);
    
    RectF rect1 = new RectF();              // 存放测量结果的矩形
    
    Path path = new Path();                 // 创建Path并添加一些内容
    path.lineTo(100,-50);
    path.lineTo(100,50);
    path.close();
    path.addCircle(-100,0,100, Path.Direction.CW);
    
    path.computeBounds(rect1,true);         // 测量Path
    
    canvas.drawPath(path,mDeafultPaint);    // 绘制Path
    
    mDeafultPaint.setStyle(Paint.Style.STROKE);
    mDeafultPaint.setColor(Color.RED);
    canvas.drawRect(rect1,mDeafultPaint);   // 绘制边界
    

重置路径:reset、rewind

  • 重置Path有两个方法,分别是reset()rewind(),两者区别主要有以下两点

    • reset:保留FillType设置,不保留原有数据结构
    • rewind:不保留FillType设置,保留原有数据结构
  • 建议:选择权重: FillType > 数据结构,因为“FillType”影响的是显示效果,而“数据结构”影响的是重建速度

关于Path绘制路径的常用方法总结

  • moveTo:移动起点;移动下一次操作的起点位置

  • setLastPoint:设置终点;重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同

  • lineTo:连接直线;添加上一个点到当前点之间的直线到Path

  • close:闭合路径;连接第一个点连接到最后一个点,形成一个闭合区域

  • addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo:添加内容;添加(矩形圆角矩形椭圆路径圆弧) 到当前Path (注意addArc和arcTo的区别)

  • isEmpty:是否为空;判断Path是否为空

  • isRect:是否为矩形;判断path是否是一个矩形

  • set:替换路径;用新的路径替换到当前路径所有内容

  • offset:偏移路径;对当前路径之前的操作进行偏移(不会影响之后的操作)

  • quadTo, cubicTo:贝塞尔曲线;分别为二次和三次贝塞尔曲线的方法

  • rMoveTo, rLineTo, rQuadTo, rCubicTorXxx方法不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)

  • setFillType, getFillType, isInverseFillType, toggleInverseFillType:填充模式;设置填充模式、获取填充模式、判断和切换填充模式

  • incReserve查看案例:提示方法;提示Path还有多少个点等待加入(这个方法貌似会让Path优化存储结构)

  • op:布尔操作(API19);对两个Path进行布尔运算(区域分割交集处理)

  • computeBounds:计算边界;计算Path的边界

  • reset, rewind:重置路径;清除Path中的内容,reset不保留内部数据结构,但会保留FillType;rewind会保留内部的数据结构,但不保留FillType

  • transform:矩阵操作;矩阵变换坐标位置

标签:Canvas,RectF,坐标,path,Path,Android,100,500
From: https://www.cnblogs.com/ajunjava/p/18324244

相关文章

  • Hadoop(5-1) HBase 提示SLF4J: Class path contains multiple SLF4J bindings.
    Hadoop(5-1)HBase提示SLF4J:ClasspathcontainsmultipleSLF4Jbindings.问题描述在使用hbaseversion命令时,出现下列的警告信息 。SLF4J:ClasspathcontainsmultipleSLF4Jbindings.SLF4J:Foundbindingin[jar:file:/usr/local/hadoop-3.3.6/share/hadoop/com......
  • fastJson对jsonPath的支持
    使用场景很多时候我们调用上游接口拿到的返回值是json字符串,如果不存在上游共享的公用返回值类,那么下游可能会直接使用JsonObject之类的动态对象类承接这份数据。这时候对于很深的的属性取值是非常复杂的我们大概会这样写Stringgetvalue(StringjsonStr){JSONObjectjson......
  • LeetCode 864. Shortest Path to Get All Keys
    原题链接在这里:https://leetcode.com/problems/shortest-path-to-get-all-keys/description/题目:Youaregivenan mxn grid grid where:'.' isanemptycell.'#' isawall.'@' isthestartingpoint.Lowercaselettersrepresentkeys.U......
  • 在 Python Notebook 中调用 `subprocess` 具有与 `!` shell 不同的 `$PATH`
    我正在IPython笔记本中交互地开发一个包装类。这个包装类调用用java编写的命令行程序,因此我需要访问用于编译该程序的相同版本的java运行时。但是,我注意到在笔记本中使用方便的!运算符,生成的shell实例与在我的终端中使用zsh时不同。这得到了确......
  • 在 VSCode 中激活 conda env 时,“which python”和“sys.path”给出不同的输出
    当我激活condaenv时,选择相应的解释器并在VScode中启动Python乍一看一切似乎都很好:(My_env)name@my_computer:~/Bureau/My_env/Code/current_dir$/home/name/anaconda3/envs/My_env/bin/python-mIPython--no-autoindentPython3.12.4|packagedb......
  • Android 10.0 Settings 加载流程
    一、系统设置首页代码路径:packages/app/Settings/1主界面加载:<!--Aliasforlauncheractivityonly,asthisbelongstoeachprofile.--><activity-aliasandroid:name="Settings"android:label="@string/settings_label_lau......
  • Canvas+bpmn.js 流程节点鼠标悬浮显示信息 (全网首发)
    customBpmn.jsimportinheritsfrom"inherits";importViewerfrom"bpmn-js/lib/Viewer";importZoomScrollModulefrom"diagram-js/lib/navigation/zoomscroll";importMoveCanvasModulefrom"diagram-js/lib/navigation/moveca......
  • kotlin,Android教你最基础的ViewBinding视图绑定
    目录一.添加依赖二.在Activity中使用ViewBinding修改布局文件修改kt文件 效果三.在Fragment中使用ViewBinding修改布局文件修改kt文件效果不玩虚的,就三分钟,看完就能学会最基础的ViewBinding如何使用使用ViewBinding有什么好处呢与使用findViewById相比,视图绑......
  • Android中的usescleartexttraffic属性详解
    Android中的usescleartexttraffic属性详解usesCleartextTraffic是Android应用程序开发中的一个重要配置选项,用于控制应用程序是否允许通过不加密的HTTP协议进行网络通信。在Android应用的开发过程中,正确地配置usesCleartextTraffic对于保护用户数据安全、符合最佳......
  • Android Spingboot 实现SSE通信案例
    SSESSE(Server-SentEvents)是一种用于实现服务器主动向客户端推送数据的技术,它基于HTTP协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。Server-SentEvents(SSE)和Sockets都可以用于实现服务器向客户端推......