android 自定义控件--Path 基本用法

Path 使用方法详解

此篇是看了一名来自2.5次元的魔法师的文章后做的笔记,原文http://www.gcssloop.com/customview/Path_Bezier,大家可以看下,文很棒

1. 第一组:moveTo、setLastPoint 、lineTo 、close

方法:lineTo

public void lineTo (float x, float y)

例:画两条线

 public PathView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //初始化画笔
        mPaint = new Paint();             // 创建画笔
        mPaint.setColor(Color.BLACK);           // 画笔颜色 - 黑色
        mPaint.setStyle(Paint.Style.STROKE);    // 填充模式 - 描边
        mPaint.setStrokeWidth(10);              // 边框宽度 - 10

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        //获取宽高
        width = h;
        height = w;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)

        Path path = new Path();                     // 创建Path

        path.lineTo(200, 200);                      // lineTo 从默认点0,0到 200,200
        path.lineTo(200, 0);                        //再从200,200 到点 200,0

        canvas.drawPath(path, mPaint);              // 绘制Path
    }

结果如图,黑色线图像为结果,图中添加坐标系,有利于理解

这里写图片描述

Path 默认点是坐标原点0,0
事例代码中调用了两次lineTo,

第一次:path.lineTo(200, 200); //从0,0 到点A(200,200)的连线
第二次:path.lineTo(200, 0);//从A(200,200) 到点 B(200,0)的连线

方法 moveTo 和 setLstPoint

// moveTo
public void moveTo (float x, float y)

// setLastPoint
public void setLastPoint (float dx, float dy)
方法名 简介 是否影响之前操作 是否影响之后操作
moveTo 移动下一次操作的起点位置
setLastPoint 设置之前操作的最后一个点位置

方法 moveTo

例:

canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
Path path = new Path();                     // 创建Path
path.lineTo(200, 200);                      // lineTo 从默认点0,0到 200,200
path.moveTo(200, 100);                      // moveTo 改变下一个点开始的位置
path.lineTo(200, 0);                        // 由于moveTo改变了开始位置,所以从200,100 到点 200,0
canvas.drawPath(path, mPaint);              // 绘制Path

这里写图片描述

moveTo只改变下次操作的起点,在执行完第一次LineTo的时候,本来的默认点位置是A(200,200),但是moveTo将其改变成为了C(200,100),所以在第二次调用lineTo的时候就是连接C(200,100) 到 B(200,0) 之间的直线

方法setLstPoint

例:

canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
        Path path = new Path();                     // 创建Path
        path.lineTo(200, 200);                      // lineTo 从默认点0,0到 200,200
//        path.moveTo(200, 100);                      // moveTo 改变下一个点开始的位置
        path.setLastPoint(200,100);                 // setLastPoint 改变上一个点结束的位置
        path.lineTo(200, 0);                        // 由于moveTo改变了开始位置,所以从200,100 到点 200,0
        canvas.drawPath(path, mPaint);              // 绘制Path

效果:
这里写图片描述

在执行完第一次的lineTo的时候,最后一个点是A(200,200),而setLastPoint更改最后一个点为B(200,200)为(200,100),所以在实际执行的时候,第一次的lineTo就不是从原点O到A(200,200)的连线了,而变成了从原点O到C(200,100)之间的连线了。

方法 close

public void close()

用于连接当前最后一个点和最初的点(如果两个点不重合),形成一个闭合的图形

结果:
这里写图片描述

2. 第二组:addXxx 与 arcTo

第一类(基本形状)

// 圆形
public void addCircle (float x, float y, float radius, Path.Direction dir)
// 椭圆
public void addOval (RectF oval, Path.Direction dir)
// 矩形
public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
public void addRect (RectF rect, Path.Direction dir)
// 圆角矩形
public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)

最后一个参数都是Path.Direction,意思是方向,绘制时点是你是逆时针还是顺时针,在添加图形时确定闭合顺序(各个点的记录顺序)

类型 含义
CW 顺时针
CCW 逆时针

例子:画一个矩形,顺时针

canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心
Path path = new Path();
path.addRect(-200, -200, 200, 200, Path.Direction.CW);//顺时针
canvas.drawPath(path, mPaint);

结果:
这里写图片描述

其实顺时针和逆时针的表面结果是一样的,只是过程不同,是怎么画成的

第二类方法(Path)

// path
public void addPath (Path src)
public void addPath (Path src, float dx, float dy)
public void addPath (Path src, Matrix matrix)

第一个方法:将两个Path合并成为一个

第二个方法比第一个方法多出来的两个参数是将src进行了位移之后再添加进当前path中。

第三个方法是将src添加到当前path之前先使用Matrix进行变换。

例子:

       canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心
        canvas.scale(1,-1);                         // <-- 注意 翻转y坐标轴

        Path path = new Path();
        Path src = new Path();

        path.addRect(-200,-200,200,200, Path.Direction.CW);//绘制一个矩形
        src.addCircle(0,0,100, Path.Direction.CW);//坐标原点绘制一个圆形

        path.addPath(src,0,200);//将圆形添加到矩形的上 0,200的位置

        canvas.drawPath(path,mPaint);

结果:
这里写图片描述

第三类方法(addArc与arcTo)

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

方法区别

名称 作用 区别
addArc 添加一个圆弧到path 直接添加一个圆弧到path中
arcTo 添加一个圆弧到path 添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点

参数含义

参数 含义
oval 圆弧的外切矩形
startAngle 开始角度
sweepAngle 扫过角度(-360 <= sweepAngle < 360)
forceMoveTo 是否强制使用MoveTo

sweepAngle取值范围是 [-360, 360),不包括360,当 >= 360 或者 < -360 时将不会绘制任何内容, 对于360,你可以用一个接近的值替代,例如: 359.99

foreMoveTo 含义 等价方法
true 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 public void addArc (RectF oval, float startAngle, float sweepAngle)
false 不移动,而是连接最后一个点与圆弧起点 public void arcTo (RectF oval, float startAngle, float sweepAngle)

例子(addArc):

canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心
canvas.scale(1,-1);                       // <-- 注意 翻转y坐标轴
Path path = new Path();
path.lineTo(100,100);                       //先画个线

RectF oval = new RectF(0,0,300,300);        //确定圆弧的外切矩形的位置

path.addArc(oval,0,270);                    //在已有的线的基础上添加圆弧
 // path.arcTo(oval,0,270,true);             // <-- 和上面一句作用等价

 canvas.drawPath(path,mPaint);

结果:
这里写图片描述

例子(arcTo):

 canvas.translate(width / 2, height / 2);  // 移动坐标系到屏幕中心
 canvas.scale(1,-1);                         // <-- 注意 翻转y坐标轴

        Path path = new Path();
        path.lineTo(100,100);                       //先画个线

        RectF oval = new RectF(0,0,300,300);        //确定圆弧的外切矩形的位置

        path.arcTo(oval,0,270);                      //在已有的线的基础上添加圆弧,不移动,而是连接最后一个点与圆弧起点
        // path.arcTo(oval,0,270,false);             // <-- 和上面一句作用等价

        canvas.drawPath(path,mPaint);

结果:
这里写图片描述

3. isEmpty 、isRect、 isConvex、 set 、offset

方法: isEmpty

判断path中是否包含内容。

Path path = new Path();
Log.e("1",path.isEmpty()+"");

path.lineTo(100,100);
Log.e("2",path.isEmpty()+"");

结果:

com.sloop.canvas E/1: true
com.sloop.canvas E/2: false

方法:isRect

public boolean isRect (RectF rect)

判断path是否是一个矩形,如果是一个矩形的话,会将矩形的信息存放进参数rect中

path.lineTo(0,400);
path.lineTo(400,400);
path.lineTo(400,0);
path.lineTo(0,0);

RectF rect = new RectF();
boolean b = path.isRect(rect);
Log.e("Rect","isRect:"+b+"| left:"+rect.left+"| top:"+rect.top+"| right:"+rect.right+"| bottom:"+rect.bottom);

结果:

com.sloop.canvas E/Rect: isRect:true| left:0.0| top:0.0| right:400.0| bottom:400.0

方法:set

public void set (Path src)

将新的path赋值到现有path。

canvas.translate(mWidth / 2, mHeight / 2);  // 移动坐标系到屏幕中心
canvas.scale(1,-1);                         // <-- 注意 翻转y坐标轴

Path path = new Path();                     // path添加一个矩形
path.addRect(-200,-200,200,200, Path.Direction.CW);

Path src = new Path();                      // src添加一个圆
src.addCircle(0,0,100, Path.Direction.CW);

path.set(src);                              // 大致相当于 path = src;

canvas.drawPath(path,mPaint);

结果:
这里写图片描述

方法 offset

public void offset (float dx, float dy)
public void offset (float dx, float dy, Path dst)

对path进行一段平移,它和Canvas中的translate作用很像,但Canvas作用于整个画布,而path的offset只作用于当前path。

方法第最后的参数 Path dst 是存储平移后的path的

dst状态 效果
dst不为null 将当前path平移后的状态存入dst中,不会影响当前path
dat为空 平移将作用于当前path,相当于第一种方法
// ====== 方法 offset ========
        canvas.translate(width/2 , height / 2);  // 移动坐标系到屏幕中心
        canvas.scale(1,-1);                         // <-- 注意 翻转y坐标轴

        Path path = new Path();                     // path中添加一个圆形(圆心在坐标原点)
        path.addCircle(0,0,100, Path.Direction.CW);

        Path dst = new Path();                      // dst中添加一个矩形
        dst.addRect(-200,-200,200,200, Path.Direction.CW);

        path.offset(250,0,dst);                     // 平移
        canvas.drawPath(path,mPaint);               // 绘制path
        mPaint.setColor(Color.BLUE);                // 更改画笔颜色
        canvas.drawPath(dst,mPaint);                // 绘制dst

结果:
平移之前:
这里写图片描述

平移后:
这里写图片描述

从运行效果图可以看出,虽然我们在dst中添加了一个矩形,但是并没有表现出来,所以,当dst中存在内容时,dst中原有的内容会被清空,而存放平移后的path。

发布了33 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hjiangshujing/article/details/76615796