zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android Canvas之Path的详解与使用(二)

Android 详解 path Canvas 使用
2023-09-27 14:27:35 时间

Path:

Path类封装复合(多轮廓)几何路径由直线段、二次曲线和三次曲线组成。它可以用画布绘制。drawPath(路径、绘制),填充或笔划(基于绘画的样式),或者可以用于剪裁或绘制路径上的文本。

Path属于路径,路径走多了就变成一种套路,只要我们会解套,那这种套路就是高速公路。路径走完形成闭环,最终形成一个图形。

path的合作伙伴是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.Style.FILL_AND_STROKE:会出现角有缺陷,在使用需要注意
paint.setStyle(Paint.Style.STROKE);
   paint.setStyle(Paint.Style.STROKE);
paint.setStyle(Paint.Style.FILL);

 

paint.setStyle(Paint.Style.FILL_AND_STROKE);

 

 

一、Path的使用

1.构造一个path对象

1.1:构造一个空对象

public Path()

1.2 拷贝一个对象
public Path(Path src) 

二、Path的方法介绍

2.1:moveTo(x,y);

path默认的起始坐标是0,0;如果想改变起始坐标,通过moveTo来设置

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


    }

 

 图一是没设置moveTo,默认(0,0)坐标,图二是moveTo(100,100)新的坐标点

 

2.2rLineTo

与lineTo相同,但坐标被视为相对于最后一个此轮廓上的点。如果没有上一个点,则将moveTo(0,0)将自动插入。

说明:这里有三个点A(0,0)B(0,1000)C(1000,0)

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

LineTo:直接将A、B、C三个点按顺序在view中连起来

    private void rLineTo(Path path) {

        path.rLineTo(0, 1000);
        path.rLineTo(1000, 0);

    }

rLineTo

LineTo

 

 2.3贝塞尔曲线:quadTo

public void quadTo(float x1, float y1, float x2, float y2)

一般曲线是由三个点完成,开始,顶点,结束。在而塞尔曲线中,

(x1,y1)为曲线的顶点

(x2,y2)为曲线的结束点

开始默认是(0,0),可以通过moveTo来改变


    private void quadTo(Path path) {
        path.moveTo(100, 0);
        path.quadTo(100, 1000, 1000, 0);
    }

  2.4贝塞尔曲线:rQuadTo

与quadTo相同,但坐标被视为相对于最后一个此轮廓上的点。如果没有上一个点,则将moveTo(0,0)将自动插入。

可参考上方

2.5立方贝塞尔:cubicTo

public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 

从接近控制点的最后一点添加一个立方贝塞尔(x1,y1)和(x2,y2),并在(x3,y3)处结束。如果没有moveTo()调用对于此轮廓,第一个点自动设置为(0,0)

    private void cubicTo(Path path) {

        int width=getWindowSize(0)/2;
        int height=getWindowSize(1)/2;

        path.cubicTo(0, height, width, height, width, 0);
    }

 

2.6圆弧:arcTo

public void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

将指定的圆弧作为新轮廓附加到路径。如果开始路径与路径的当前最后一点不同,则添加了automatic lineTo()以将当前轮廓连接到弧的起点。但是,如果路径为空,则调用moveTo()弧的第一点

oval:扇形图形view大小

startAngle:开始角度

sweepAngle:扇形角度

forceMoveTo:如果为真,则始终以圆弧开始新轮廓

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

    }
paint.setStyle(Paint.Style.STROKE)
 
paint.setStyle(Paint.Style.FILL)

 

2.7关闭当前轮廓 :close

关闭当前轮廓。如果当前点不等于轮廓的第一个点,自动添加线段。

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

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

调用close():三个点,首位相连

 

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

 

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

public void addRect(RectF rect, Direction dir) 

rect:矩形区域

dir:缠绕矩形轮廓的方向,CW=顺时针,CCW=逆时针

private void addRect(Path path)
    {

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

    }

2.9绘制椭圆:addOval

 

public void addOval(RectF oval, Direction dir)
    private void addOval(Path path) {
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addOval(rect, Path.Direction.CCW);
    }

注意:如果矩形是正方形绘制出来的图形是圆形

 2.10绘制圆形:addCircle

public void addCircle(float x, float y, float radius, Direction dir)

(x ,y):圆心的坐标

radius:半径

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

 2.11在矩形区域画弧度:addArc

public void addArc(RectF oval, float startAngle, float sweepAngle)

如果这个矩形是一个正方形,那么画出来的弧度是半圆形,否则是一个不规则的股弧度

    private void addArc(Path path) {
        paint.setStyle(Paint.Style.STROKE);
        RectF rect = new RectF(0, 0, 500, 500);
        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);

}

 

    private void addArc(Path path) {
        paint.setStyle(Paint.Style.FILL);
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addArc(rect,0,180);

    }

 

    private void addArc(Path path) {
        paint.setStyle(Paint.Style.STROKE);
        RectF rect = new RectF(0, 0, 1000, 500);
        path.addArc(rect,0,180);

    }

 2.12在矩形中绘制一个圆形:addRoundRect

public void addRoundRect(RectF rect, float rx, float ry, Direction dir)

(rx,ry)代表圆形在矩形中的中心坐标,如果这个坐标正在矩形的正中心,那绘制出来的正好是圆形,否则距离中心远近代表角度的大小

注意:这里面rx或者ry中,只要有一个角的坐标为0,都无法生效。

rx和ry其实看成到各个顶点的角度百分比。

rx=ry,四个角大小是一致,否则不一样

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

 

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

 

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

 

2.13在path中添加新的path :addPath

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

matrix和(dx,dy)可以指定src在path中的坐标,类似View在viewGroup的坐标。如果没有,默认覆盖在父path的view上,坐标dx=dy=0;

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

    }

2.14整体偏移 :offset

offset是针对整个path来完成偏移的,而不是某个点,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);


    }

 

 

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

正常如下:

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

    }

正常
path.setLastPoint(500,500)

 

 

2.16 path的控制:transform

通过Matrix对path的路径进行控制和操控,比offset更灵活,只要操作Matrix即可完成当前path的变种


三、关于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分别为二次和三次贝塞尔曲线的方法
rXxx方法rMoveTo, rLineTo, rQuadTo, rCubicTo不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)
填充模式setFillType, getFillType, isInverseFillType, toggleInverseFillType设置,获取,判断和切换填充模式
提示方法incReserve提示Path还有多少个点等待加入(这个方法貌似会让Path优化存储结构)
布尔操作(API19)op对两个Path进行布尔运算(即取交集、并集等操作)
计算边界computeBounds计算Path的边界
重置路径reset, rewind清除Path中的内容
reset不保留内部数据结构,但会保留FillType.
rewind会保留内部的数据结构,但不保留FillType
矩阵操作transform矩阵变换