自定义View-第七步:Path基础

前言

根据Gcssloop所学习的自定义View整理与笔记。

请关闭硬件加速,以免引起不必要的问题!
在AndroidMenifest文件中application节点下添上 android:hardwareAccelerated=”false”以关闭整个应用的硬件加速。

一、Path的常用方法【look一下,后续会详解的O(∩_∩)O~】

|作用|相关方法|备注|
|------|-----|----|
|移动起点|moveTo|移动下一次操作的起点位置|
|设置终点|setLastPoint|重置当前Path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同|
|连接直线|lineTo|添加上一个点到当前点的直线到path|
|闭合路径|close|连接第一个点到最后一个点,形成一个闭合区域|
|添加内容|addRect,addRoundRect,addOval,addCircle,addPath,addArc,arcTo|添加(矩形,圆角矩形,椭圆,圆,路径,圆弧)到当前path|
|是否为空|isEmpty|判断path是否为空|
|是否为矩形|isRect|判断path是否是一个矩形|
|替换路径|set|用新的路径替换到当前路径所有内容|
|偏移路径|offset|对当前路径之前的操作进行偏移(不会影响之后的操作)|
|贝塞尔曲线|quadTo,cubicTo|分别为二次和三次贝塞尔曲线的方法|
|rXxx方法|rMoveTo, rLineTo, rQuadTo, rCubicTo|不带r的方法是基于原点的坐标系(偏移量),rXxx方法是基于当前点坐标系(偏移量),即以path最后的那个点|
|填充模式|setFillType, getFillType, isInverseFillType, toggleInverseFillType|设置,获取,判断和切换填充模式|
|提示方法|incReserve|提示path还有多少个点等待加入(可能会让path优化存储结构)|
|布尔操作【api19】|op|对两个path进行布尔运算,【即取交集,并集等操作】|
|计算边界|computeBounds|计算Path的边界|
|重置路径|reset,rewind|清除path中的内容【reset不保留内部数据结构,但会保留FillType,rewind会保留内部的数据结构,但不保留FillType】【FillType影响的是显示效果,数据结构影响重建速度】
|矩阵操作|transform|矩阵变换|

二、Path详解

看着多,其实就一点点,敲敲代码,瞬间理解,真的

1. lineTo

paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
canvas.translate(300,300);
Path path = new Path(); 
path.lineTo(200, 200); 
path.lineTo(200,0);
canvas.drawPath(path, paint); // 绘制Path

效果图:


lineTo效果图

2.moveTo与setLastPoint


// moveTo,移动下一次操作的起点位置,不影响之前的操作,只影响之后的操作
public void moveTo (float x, float y)
// setLastPoint,设置之前操作的最后一个点的位置,影响之前和之后的操作
public void setLastPoint (float dx, float dy)

demo [moveTo]:

       canvas.translate(200, 200);
        Path path = new Path();
        path.lineTo(200, 200);
        path.moveTo(200,100);
        path.lineTo(200, 0);
        canvas.drawPath(path, paint);
moveTo效果图

demo [setLastPoint]:

        canvas.translate(200, 200);
        Path path = new Path();
        path.lineTo(200, 200);
        path.setLastPoint(200,100);
        path.lineTo(200, 0);
        canvas.drawPath(path, paint);
setLastPoint效果图

3. rLineTo与lineTo方法

       canvas.translate(100, 100);
        Path path = new Path();
//lineTo
        path.lineTo(200, 200);
        path.lineTo(200, 100);
//rLineTo
        path.rLineTo(200, 100);
      //  path.lineTo(0, 0);①
        canvas.drawPath(path, paint);

lineTo与rLineTo效果图.png

注释
translate将坐标移动到屏幕(100,100)的位置,也就是图上标注坐标原点的部分,那么lineto将均以该坐标为坐标原点rlineto执行前的点为(200,100),此时,会以(200,100)为坐标原点,即下一个点的实际位置为(400,200),当然,实际坐标的位置是不会改变的,如果在①执行的话,会发现添加了从(400,200)到(0,0)[即图上标注坐标原点] 的直线。
也就是说,lineTo和rLineTo的参考坐标不一样。
请原谅我叙述的本领,如果不清楚的话,就自己写个demo试试吧O(∩_∩)O~

4.close方法
用于连接当前最后一个点和最初的一个点(如果两个点不重合的话),最终形成一个封闭的图形,如果连接了最后一个点和第一个点仍然无法形成封闭图形,则close什么也不做

        canvas.translate(100, 100);
        Path path = new Path();
        path.lineTo(200, 200);
        path.lineTo(200, 0);
        path.close();
        canvas.drawPath(path, paint);
close效果图

实体三角形这样画

       paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.GREEN);
        Path path = new Path();
        path.moveTo(80, 200);// 此点为多边形的起点
        path.lineTo(120, 250);
        path.lineTo(80, 250);
        path.close(); // 使这些点构成封闭的多边形
        canvas.drawPath(path, paint);
三角形

5.addXxx与arcTo,注意区分addArc与arcTo

** 1. 基本图形**

// 圆形
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:逆时针
    cw demo:
        canvas.translate(250, 250);
        Path path = new Path();
        //得到一个矩形,顺时针绘制矩形,左下角为最后一个点,获得①
        path.addRect(-100,-100,200,200, Path.Direction.CW);
        canvas.drawPath(path,paint);
        //重置最有后一个点的位置,获得②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一个矩形,获得③
        path.addRect(-160,-160,260,260,Path.Direction.CW);
        canvas.drawPath(path, paint);
效果图.png

这个时候把③注释,

     canvas.translate(250, 250);
        Path path = new Path();
        //得到一个矩形①
        path.addRect(-100,-100,200,200, Path.Direction.CW);
       // canvas.drawPath(path,paint);
        //重置最后一个点的位置②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一个矩形③
       //  path.addRect(-160,-160,260,260,Path.Direction.CW);
      // canvas.drawPath(path, paint);

则得到如下效果:


内心崩溃.jpg

为啥缺了一角?哈哈,因为没关闭硬件加速,记得关闭硬件加速哦,效果就是这样子的啦:

完美.jpg

ccw demo:

        canvas.translate(250, 250);
        Path path = new Path();
        //得到一个逆时针绘制的矩形,右上角为最后的一个点①
        path.addRect(-100,-100,200,200, Path.Direction.CCW);
        //重置最后一个点的位置②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一个矩形③
        path.addRect(-160,-160,260,260,Path.Direction.CW);
        canvas.drawPath(path, paint);

为了显示隐藏的那一角,我们还将③执行哈:


ccw效果图

2. addPath:将两个Path合并成为一个

public void addPath (Path src)
//将src进行了位移之后再添加进当前path中
public void addPath (Path src, float dx, float dy)
//将src使用Matrix进行变换后再添加到当前path中,同样的,Matrix后续讲解
public void addPath (Path src, Matrix matrix)

demo:

       canvas.translate(250, 250);
        Path path = new Path();
        Path src = new Path();
        path.addRect(-100,-100,200,200, Path.Direction.CCW);
        path.setLastPoint(-150,250);
        src.addRect(-160,-160,260,260,Path.Direction.CW);
     //合并路径
        path.addPath(src);
    //绘制合并后的路径
        canvas.drawPath(path, paint);

效果图和ccw效果图是一样滴,看上面最后一张图⤴️~

3.addArc与arcTo:添加一个圆弧到path

// 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)
  • oval:圆弧的外切矩形
  • startAngle:开始角度
  • sweepAngle: 扫过角度(-360<=sweepAngle<360),当 >= 360 或者 < -360 时将不会绘制任何内容
  • forceMoveTo:是否强制使用MoveTo

addArc与arcTo的区别:

  1. addArc:直接添加一个圆弧到path中
  2. arcTo:添加一个圆弧到path,如果圆弧的起点和路径上次最后一个坐标点不相同,就连接两个点
    不过->如果有forceMoveTo,还是要看forceMoveTo的取值的哦。
forceMoveTo 含义 等价方法
true 不连接最后一个点与圆弧起点,不补全路径 public void addArc (RectF oval, float startAngle, float sweepAngle)
false 连接最后一个点与圆弧起点,即补全路径 public void arcTo (RectF oval, float startAngle, float sweepAngle)

看下边demo了解一下区别⤵️
demo addArc (arcTo true):

        canvas.translate(250, 250);
        Path path = new Path();
        path.lineTo(100, 100);
        
        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawRect(rectF, paint);
        
        path.addArc(rectF, 0, 230);
        //等价于下边的作用
        // path.arcTo(rectF,0,230,true);
        canvas.drawPath(path, paint);
addArc效果图

demo arcTo (arcTo false):

   canvas.translate(250, 250);
        Path path = new Path();
        path.lineTo(100, 100);

        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawRect(rectF, paint);

        path.arcTo(rectF, 0, 230);
        //等价于下边的作用
        //path.arcTo(rectF, 0, 230, false);
        canvas.drawPath(path, paint);
arcTo效果图

OK啦,这就是区别了,简单来说,就是是否自动补全路径。

4.isEmpty、 isRect、 set 和 offset

  1. isRect:
        Path path = new Path();
        Log.d("isEmpty1","isEmpty"+path.isEmpty());
        path.lineTo(100, 100);
        Log.d("isEmpty2","isEmpty"+path.isEmpty());
  /**
  *结果如下:
  * D/isEmpty1: isEmptytrue
  * D/isEmpty2: isEmptyfalse
  1. isRect:判断path是否是一个矩形,如果是一个矩形的话,会将矩形的信息存放进参数rect中。
       canvas.translate(50, 50);
        Path path = new Path();
        path.lineTo(0,400);
        path.lineTo(400,400);
        path.lineTo(400,0);
        path.lineTo(0,0);
        RectF rectF = new RectF();
        boolean rect = path.isRect(rectF);
        Log.d("isRect","isRect"+rect+"left:"+rectF.left);
/**
*结果是:
 *D/isRect: isRecttrueleft:0.0
**/
  1. set
       canvas.translate(160, 160);
        Path path = new Path(); 
        path.addRect(0, 0, 200, 200, Path.Direction.CW);

        Path src = new Path(); 
        src.addCircle(0, 0, 100, Path.Direction.CW);
        path.set(src); 
        canvas.drawPath(path, paint);
结果是一个圆
  1. offset:对path进行一段平移,只作用于当前的path
        public void offset (float dx, float dy)
        public void offset (float dx, float dy, Path dst)
  • Path dst:存储平移后的path
    1. dst不为空:将当前path平移后的状态存入dst中,不会影响当前path
    2. dst为空(null) :平移将作用于当前path,相当于第一种方法

补充

还记得上一节我们还没讲的方法么?根据路径绘制文字

public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
public void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
  • text指文本内容
  • hOffset参数指定水平偏移
  • vOffset指定垂直偏移
        paint.setTextSize(24);
        paint.setColor(Color.BLUE);
        Path path = new Path();
        path.addArc(new RectF(0,0,100,100),10,209);
        canvas.drawTextOnPath("hello world hello world hello world ",path,0,0,paint);
效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容