android Path的使用

参考:
android绘图之Path总结
Path相关方法讲解(一)
path类的简化结构图


类结构图

内部枚举类

//用于对两个Path对象做相应的运算组合(combine),具体的说是根据不同的op参数及path2参数来影响path1对象,
enum Op:五个枚举值:DIFFERENCE,INTERSECT,UNION,XOR,REVERSE_DIFFERENCE
//填充模式:
enum FillType:四种FillType,WINDING,EVEN_ODD,INVERSE_WINDING,INVERSE_EVEN_ODD 
//往path里添加矩形或圆时候用来指明放心:顺时针或逆时针
enum Direction

构造方法

构造函数有两个,分别是:

/**  
 * Create an empty path  
 */  
public Path() {  
    mNativePath = init1();  
    mDetectSimplePaths = HardwareRenderer.isAvailable();  
}  

/**  
 * Create a new path, copying the contents from the src path.  
 *  
 * @param src The path to copy from when initializing the new path  
 */  
public Path(Path src) {  
    int valNative = 0;  
    if (src != null) {  
        valNative = src.mNativePath;  
    }  
    mNativePath = init2(valNative);  
    mDetectSimplePaths = HardwareRenderer.isAvailable();  
}  

这没啥好说的,第二种就是直接复用src 里设置的属性创建一个新的Path对象;

常用方法

  1. 基本绘图方法
1.addArc(RectF oval, float startAngle, float sweepAngle)
     绘制弧线,配合Paint的Style可以实现不同的填充效果
2.addCircle(float x, float y, float radius, Path.Direction dir)
     绘制圆形,其中第dir参数用来指定绘制时是顺时针还是逆时针
3.addOval(RectF oval, Path.Direction dir)
     绘制椭圆形,其中 oval作为椭圆的外切矩形区域
4.addRect(RectF rect, Path.Direction dir)
     绘制矩形
5.addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)
     绘制圆角矩形
6.lineTo(float x, float y)
     绘制直线
7.addPath(Path src)
     添加一个新的Path到当前Path
8.arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
     与addArc方法相似,但也有区别,下文细述。
9.quadTo(float x1, float y1, float x2, float y2)
     绘制二次贝塞尔曲线,其中 (x1,y1)为控制点,(x2,y2)为终点
10.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
     绘制三次贝塞尔曲线,其中(x1,y1),(x2,y2)为控制点,(x3,y3)为终点
  1. rXXX方法
    上面的lineTo,MoveTo,QuadTo,CubicTo方法都有与之对应的rXXX方法:
rLineTo(float dx, float dy)
rMoveTo(float dx, float dy)
rQuadTo(float dx1, float dy1, float dx2, float dy2)
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

这些方法与之对应的原方法相比,惟一的区别在于:r方法是基于当前绘制开始点的offest,比如当前paint位于 (100,100)处,则使用rLineTo(100,100)
方法绘制出来的直线是从(100,100)到(200,200)的一条直接,由此可见rXXX
方法方便用来基于之前的绘制作连续绘制。

  1. Path.op方法
    此方法用于对两个Path对象做相互运算,类似于:与、或、异或之类
path1.op(path2,Path.Op.XXX);

例子:

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.UNION);
canvas.drawPath(path1, paint1);

效果如下:

Path.Op.UNION
Path.Op.DIFFERENCE
效果:

Path.Op.INTERSECT
效果:

Path.Op.REVERSE_DIFFERENCE
效果:

Path.Op.XOR
效果:

总结:
Path.Op.DIFFERENCE 减去path1中path1与path2都存在的部分;path1 = (path1 - path1 ∩ path2)
Path.Op.INTERSECT 保留path1与path2共同的部分;path1 = path1 ∩ path2
Path.Op.UNION 取path1与path2的并集;path1 = path1 ∪ path2
Path.Op.REVERSE_DIFFERENCE 与DIFFERENCE刚好相反;path1 = path2 - (path1 ∩ path2)
Path.Op.XOR 与INTERSECT刚好相反;path1 = (path1 ∪ path2) - (path1 ∩ path2)

  1. setFillType
    设置path的填充模式.和op类似。android里定义了四种FillType,分别是:
WINDING (0),
EVEN_ODD (1),
INVERSE_WINDING (2),
INVERSE_EVEN_ODD (3)

有张图可以专门用来说明这四种模式的差别:


FillType

参考代码:

public class PathFillTypeView extends View {
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Path mPath;

    public PathFillTypeView(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);

        mPath = new Path();
        mPath.addCircle(40, 40, 45, Path.Direction.CCW);
        mPath.addCircle(80, 80, 45, Path.Direction.CCW);
        mPath.addCircle(120, 120, 45, Path.Direction.CCW);
    }

    private void showPath(Canvas canvas, int x, int y, Path.FillType ft,
                          Paint paint) {
        canvas.save();
        canvas.translate(x, y);
        canvas.clipRect(0, 0, 160, 160);
        canvas.drawColor(Color.WHITE);
        mPath.setFillType(ft);
        canvas.drawPath(mPath, paint);
        canvas.restore();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = mPaint;
        paint.setColor(Color.RED);
        canvas.drawColor(0xFFCCCCCC);
        canvas.translate(20, 20);
        paint.setAntiAlias(true);
        showPath(canvas, 0, 0, Path.FillType.WINDING, paint);
        showPath(canvas, 160 * 2, 0, Path.FillType.EVEN_ODD, paint);
        showPath(canvas, 0, 160 * 2, Path.FillType.INVERSE_WINDING, paint);
        showPath(canvas, 160 * 2, 160 * 2, Path.FillType.INVERSE_EVEN_ODD, paint);
    }
}

效果如下:
FillType

其他方法

close():闭合当前路径 (系统会自动从起点到终点绘制一条直线,使当前路径闭合)
path.reset():清除掉path里的线条和曲线,但是不会改变它的fill-type(后面setFillType再说);
path.rewind():清除掉path里的线条和曲线,但是会保留内部的数据结构以便重用;
path.set(Path src);用src的内容替换原path的内容,和硬件加速有关,开启的话有可能出不来效果。
isInverseFillType():是否是 逆 填充模式:WINDING 和 EVEN_ODD 返回false,INVERSE_WINDING 和 INVERSE_EVEN_ODD 返回true;
toggleInverseFillType():切换相反的填充模式,如WINDING ->INVERSE_WINDING 
isEmpty():path是否为空,如果path不包含任何线条和曲线,则返回true,否则返回false;
isRect(RectF rect):如果path指定的是一个rect,则返回true,否则返回false,如果返回true & rect 不为null,则将该rect设置为path 的区域;
computeBounds(RectF bounds,boolean exact):计算path所在区域,并将结果写入bounds,如果整个path只包含0或1个点,将返回(0,0,0,0):

关于setPath()方法注意:

path.set(Path src)可能受硬件加速影响
//父View绘制背景时把子view所在的区域过滤掉不绘制(不太可取)
public class ODRelativeLayout extends RelativeLayout {
    public ODRelativeLayout(Context context) {
        super(context);
    }

    public ODRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWillNotDraw(false);
    }

    public ODRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.save();
        Path path = getChildsPath();
        if(path!=null){
            path.moveTo(0,0);
            path.lineTo(getWidth(),getHeight());
            canvas.clipPath(path);
        }
        super.draw(canvas);
    }


    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.restore();
        super.dispatchDraw(canvas);
    }

    Paint paint = new Paint();
    {
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL);
    }

    private Path getChildsPath() {
        int size = getChildCount();
        if(size==0){
            return null;
        }
        Path path = new Path();
        path.setFillType( Path.FillType.INVERSE_WINDING);
        for (int i = 0; i < size; i++) {
            View cv = getChildAt(i);
            if(cv.isShown()){
                path.addRect(cv.getLeft(),cv.getTop(),cv.getRight(),cv.getBottom(), Path.Direction.CW);
            }
        }
        return path;

    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。系列教程:Android开发之从零开始系列大家要是看到有错误的...
    Anlia阅读 19,930评论 1 24
  • 最近项目中要实现加速球效果。是时候该学习一波了,好了废话不多说,记笔记,还是从自己发憷的自定义view开始。 先来...
    laifrog阅读 1,398评论 0 4
  • 版权声明:本文为博主原创文章,未经博主允许不得转载 前言 Canvas 本意是画布的意思,然而将它理解为绘制工具一...
    cc荣宣阅读 41,322评论 1 47
  • 参考:https://juejin.im/post/58ce7fe561ff4b006c9a63c6https:/...
    zhaoyubetter阅读 5,786评论 0 6
  • title: HDFS工具类date: 2016/8/26 23:51:58tags: Hadoopcategor...
    Skye_kh阅读 1,484评论 0 1