Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

android path基本使用以及贝塞尔曲线入门

$
0
0

今天周一,产品要求版本迭代到1.5.3,发现需求没啥东西,后台暂时也给不了数据,于是又有时间写博客了,这是我很喜欢的模式,今天讲下path的基本使用以及贝塞尔曲线入门,后期会讲些贝塞尔曲线结合动画的效果,瞬间让你装逼找不到自己,当然这中间需要时间去研究,这是一个快乐的过程,毕竟这是一个自己感兴趣的事,年龄大了,发现能干自己感兴趣的事还能赚钱养活自己都不容易,切入正题

Path是一个神奇的东西,能把它搞懂,可以实现网上看到的很多效果,现在开始讲下Path的基本使用

我们知道在canvas中有个方法canvas.drawPath(path,paint);这就是绘制path,path就是一条路径可以简单的理解为,google官方SDK解释:

/**
 * The Path class encapsulates compound (multiple contour) geometric paths
 * consisting of straight line segments, quadratic curves, and cubic curves.
 * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
 * (based on the paint's Style), or it can be used for clipping or to draw
 * text on a path.
 */
看不懂怎么办,没关系,我也看不懂,但是不影响你实现你想实现的效果,如果你那天成功了,谁还在意你的过去,只要你不和方舟子合不来一般是没问题的,我们学这些无非是看它的api提供了什么方法,然后每个方法有啥用,应用层就是这么玩的,

path方法如下:


path构造函数就2个,一个是无参的,一个是带参的

 public Path(Path src) 这是通过传递一个path构建一个新的path路径,现在讲讲常用的方法

1:reset() 意思是重置,其实是把你绘制在path上的图形全部清除,比如你在这path绘制了线或者点什么的,调用了reset()方法后,path上什么都没了

2:set(Path path)用传递过来的path代替之前path上的绘制的内容,这个进入源码有注释的,

3:moveTo(float startX,float endY);绘制线的起点坐标,如果不指定的话,系统默认是在原点(0,0)开始,这个写个demo就能测试出来

4:lineTo(float x,float y)这是配合moveTo()使用的,表示二个点连接成一条线,lineTo(x,y)在有moveTo()时候相当于终点,在多次调用的时候相当于起点,写个demo,说明下

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    private Path path;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.DKGRAY);
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.STROKE);
        path = new Path();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path,paint);
        path.moveTo(10,10);//起点
        path.lineTo(100,100);//终点
        path.lineTo(200,200);//这个起点是相当于 100,100
        canvas.drawPath(path,paint);
    }
}
效果:


5:rMoveTo(),rLineTo(),path类还有其他方法带r的都是相对于某一个点,rLineTo()是相当于rMoveTo()点坐标的,比如rMoveTo(10,10) 而rLine(100,100)相当于rMoveTo()起点而言,最终的绘制一条线的起点为(10,10),终点为(100+10,100+10),这个很好测试,其实你绘制线后再绘制二个终点的坐标,一看就知道了

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    private Path path,path1;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        path = new Path();
        path1 = new Path();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path.moveTo(10,10);
        path.lineTo(200,200);
        canvas.drawPath(path,paint);

        paint.setColor(Color.BLUE);
        path1.rMoveTo(100,10);
        path1.rLineTo(300,10);
        canvas.drawPath(path1,paint);

        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(8);
        //绘制2个点测试
        canvas.drawPoint(200,200,paint);
        canvas.drawPoint(400,20,paint);
    }
}
效果:


看图说话,

6:add...(),path中很多add()方法我截图看下:


什么添加椭圆 添加弧度,矩形,圆角矩形,圆形等,现在就写个添加圆形玩玩

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    path.addCircle(200,200,150, Path.Direction.CCW);
    canvas.drawPath(path,paint);
}
效果图:


你会发现path.addCircle()有一个参数Path.Direction.CCW,啥意,点击进去看源码,发现一个单词clockwise,意思是顺时针方向,那么Path.Direction.CW就是反方向了,这个你画圆时看不出来的,画什么矩形也是看不出来的,那么canvas还有一个方法,用这个方法来测试上面的2个参数什么顺时针和逆时针一眼就看的出来

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    RectF rectF = new RectF(60,60,400,400);
    path.addRect(rectF, Path.Direction.CCW);
    canvas.drawPath(path,paint);
    paint.setColor(Color.MAGENTA);
    paint.setTextSize(24);
    paint.setStrokeWidth(2);
    canvas.drawTextOnPath("杭州今天天气不错",path,0,0,paint);
}
效果:


Direction.CW 逆时针:


ok,这样直观一眼就看的出来,

7:close()闭合,就是当path绘制线大于或者等于3条的时候,使用close会构成一个封闭的图形,比如绘制三角形或者矩形

8:isEmpty()是否是空

9:isRect()是否是矩形

10:setFillType(FillType ft)填充模式:进入源码发现有如下几种:

public enum FillType {
    // these must match the values in SkPath.h
    /**
     * Specifies that "inside" is computed by a non-zero sum of signed
     * edge crossings.
     */
    WINDING         (0),
    /**
     * Specifies that "inside" is computed by an odd number of edge
     * crossings.
     */
    EVEN_ODD        (1),
    /**
     * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
     */
    INVERSE_WINDING (2),
    /**
     * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
     */
    INVERSE_EVEN_ODD(3);

    FillType(int ni) {
        nativeInt = ni;
    }

    final int nativeInt;
}
发现有四种填充模式:前提是path添加的图形要相交

WINDING:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mEndPath = new Path();
    mEndPath.offset(100,100);
    mEndPath.addCircle(200, 200, 100, Path.Direction.CW);
    mEndPath.addCircle(300, 300, 100, Path.Direction.CW);
    mEndPath.setFillType(Path.FillType.WINDING);
    paint.setColor(Color.RED);
    canvas.drawPath(mEndPath,paint);
}
效果:


EVEN_ODD:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mEndPath = new Path();
    mEndPath.offset(100,100);
    mEndPath.addCircle(200, 200, 100, Path.Direction.CW);
    mEndPath.addCircle(300, 300, 100, Path.Direction.CW);
    mEndPath.setFillType(Path.FillType.EVEN_ODD);
    paint.setColor(Color.RED);
    canvas.drawPath(mEndPath,paint);
}
效果:


INVERSE_WINDING:


INVERSE_EVEN_ODD:


没有不设置填充模式:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mEndPath = new Path();
        mEndPath.offset(100,100);
        mEndPath.addCircle(200, 200, 100, Path.Direction.CW);
        mEndPath.addCircle(300, 300, 100, Path.Direction.CW);
//        mEndPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
        paint.setColor(Color.RED);
        canvas.drawPath(mEndPath,paint);
    }
效果:


你会发现什么都没设置和WINDING模式是一样的,也就是说默认就是WINDING模式,

可能有些人会问,怎么背景会变啊,说明不是只局限我们使用path绘制的内容,而是作用于canvas上

对上面的四个模式总结:

FillType.WINDING:取path所有所在区域;

FillType.EVEN_ODD:取path所在并不相交区域;

FillType.INVERSE_WINDING:取path所有未占区域;

FillType.INVERSE_EVEN_ODD:取path未占或相交区域;

是不是可以使用这些知识把奥迪的标志绘制出来玩玩,好,动手

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    private Path path;
    private int raduis;
    private float y;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.DKGRAY);
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        path = new Path();
        raduis = 40;
        y = 60;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for(int i=1;i<5;i++){
            path.addCircle(60*i, y, raduis, Path.Direction.CW);
        }
        path.setFillType(Path.FillType.EVEN_ODD);
        canvas.drawPath(path,paint);
    }
}
效果:


是不是还可以画一个奥运的五环标志

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    private Path path;
    private int raduis;
    private float y;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.DKGRAY);
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        path = new Path();
        raduis = 60;
        y = 160;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path.addCircle(100, y, raduis, Path.Direction.CW);
        path.addCircle(230, y, raduis, Path.Direction.CW);
        path.addCircle(360, y, raduis, Path.Direction.CW);

        path.addCircle(165, 230, raduis, Path.Direction.CW);// (230-110)/2+100  这些y轴数据不是精确计算的,是估值
        path.addCircle(295, 230, raduis, Path.Direction.CW);//同理上面
        path.setFillType(Path.FillType.EVEN_ODD);
        canvas.drawPath(path,paint);
    }
}
效果:



11: public void computeBounds(RectF bounds, boolean exact)计算path绘制的内容所占的区域

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    private Path path;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.DKGRAY);
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        path = new Path();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path = new Path();
        path.offset(100,100);
        path.addCircle(200, 200, 100, Path.Direction.CW);
        path.addCircle(300, 300, 100, Path.Direction.CW);
        path.setFillType(Path.FillType.EVEN_ODD);
        RectF rectF = new RectF();
        path.computeBounds(rectF,false);
        canvas.drawPath(path,paint);
        paint.setColor(Color.RED);
        canvas.drawRect(rectF,paint);//绘制矩形 path所占的区域
    }
}
效果:


12:op(Path path, Op op)与传递进来的path与当前调用此op()方法的path通过参数op合并出一些效果,

public enum Op {
    /**
     * Subtract the second path from the first path.
     */
    DIFFERENCE,
    /**
     * Intersect the two paths.
     */
    INTERSECT,
    /**
     * Union (inclusive-or) the two paths.
     */
    UNION,
    /**
     * Exclusive-or the two paths.
     */
    XOR,
    /**
     * Subtract the first path from the second path.
     */
    REVERSE_DIFFERENCE
}
发现也有5中模式等着我去做测试了,头晕

DIFFERENCE:

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
 * Created by admin on 2016/12/7.
 */
public class PathDemo extends View {
    private Paint paint;
    public PathDemo(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(8);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        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);
        canvas.drawPath(path1, paint);
        paint.setColor(Color.DKGRAY);
        paint.setStrokeWidth(2);
        canvas.drawCircle(150, 150, 100,paint);
        canvas.drawCircle(200, 200, 100,paint);
    }
}
效果:


注:红色表示效果,绘制2个圆是做对比看的

INTERSECT:

效果:


UNION:

效果



XOR:

效果:


REVERSE_DIFFERENCE:

效果:


根据上面的效果总结:

Path.Op.DIFFERENCE:减去Path2后Path1剩下的部分 
Path.Op.INTERSECT:保留Path1与Path2共同的部分 
Path.Op.REVERSE_DIFFERENCE:减去Path1后Path2剩下的部分 
Path.Op.UNION:保留全部Path1和Path2 
Path.Op.XOR:包含Path1与Path2但不包括两者相交的部分

时候用到再来看吧,不使用记不住这些,记住了也没啥意思!头晕,写不下去了,好难受,休息,晚上再完成余下的部分!

作者:coderinchina 发表于2016/12/12 17:18:02 原文链接
阅读:43 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>