今天周一,产品要求版本迭代到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但不包括两者相交的部分

昨天龙体欠佳,晚上回去也没把博客写完,今天把余下的博客写完,ok,走入正题,开始学习贝塞尔曲线

在这就不讲什么那个牛逼的人发明了贝塞尔曲线了,要了解的话去百度百科吧,了解他,他也不会教你啥,还是要看博客自己学习,只能心里对那些牛逼的人默默的尊重和敬仰,没学贝塞尔曲线之前,我们所有的轨迹都是线性的,贝塞尔曲线分为一阶,二阶,三阶...n阶等,在sdk中只提供了二和三阶曲线的函数,哪一阶呢,其实它就是个一条直线,这会涉及到高等数学中的知识,臣妾不才,只读了个大专,大学也没上过什么高等数学的知识,全凭小学数学功底,我们学习贝塞尔曲线只要根据给的api和数学公式,学会套用就行,至于那些很复杂的,可以划分成多个二或者三阶曲线去实现,基本上需求很到,现在就开始从一阶曲线学习

一阶曲线的公式:

说明p0是起点,p1是终点,现在就套用这公式玩,

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/13.
 */
public class LineView extends View {private float startX,startY;
    private float endX,endY ;
    private Paint paint;
    private float t;
    public LineView(Context context, AttributeSet attrs) {super(context, attrs);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        startX = 100;
        startY = 100;
        endX = 300;
        endY = 300;
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        paint.setColor(Color.parseColor("#e5e5e5"));
        paint.setStrokeWidth(3);
        canvas.drawLine(startX,startY,endX,endY,paint);
        if(t>=1.0){t = 1.0f;
        }float pointX = (1-t)*startX+t*endX;
        float pointY =(1-t)*startY+t*endY;
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        canvas.drawPoint(pointX,pointY,paint);
        postDelayed(new Runnable() {@Override
            public void run() {t+=0.01;
                invalidate();
            }},50);
    }
}

效果:

可能有些人会说网上运动的是直线啊 ,没事,一样搞,

package smart.com.pathview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/12/13.
 */
public class LineView extends View {private float startX,startY;
    private float endX,endY ;
    private Paint paint;
    private float t;
    public LineView(Context context, AttributeSet attrs) {super(context, attrs);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        startX = 100;
        startY = 100;
        endX = 300;
        endY = 300;
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        paint.setColor(Color.parseColor("#e5e5e5"));
        canvas.drawLine(startX,startY,endX,endY,paint);
        if(t>=1.0){t = 1.0f;
        }float pointX = (1-t)*startX+t*endX;
        float pointY =(1-t)*startY+t*endY;
        paint.setColor(Color.RED);
        canvas.drawLine(startX,startY,pointX,pointY,paint);//绘制t在0~1时间内的运动轨迹
        postDelayed(new Runnable() {@Override
            public void run() {t+=0.01;
                invalidate();
            }},50);
    }
}

效果:

一阶曲线是没有控制点的,就只有起点和终点,

二阶曲线:

二阶曲线需要三个元素,一个是起点,二是终点,三是控制点,控制点决定了这条曲线的弯曲程度,

电脑上的画图软件相信都会知道,我们看看这个画图软件中的曲线就是一个二阶曲线,

看看二阶曲线SDK中给我们提供的api调用,封装在Path类中

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

参数说明:

x1,y1是控制点,x2,y2是终点

还有一个函数:

public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
参数说明:

(dx1,dy1)是相当于moveTo()的,不是坐标中的绝对值,而是相对于moveTo()坐标中的值,

二阶曲线的公式:

说明:

p0是起点,p1是控制点,p2是终点

现在根据这个公式,我们做一个简单的实验效果,就是控制点是我手在屏幕上移动的点,当然起点和终点肯定是已知的,不然上面那个方程怎么求,

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.MotionEvent;
import android.view.View;
/**
 * Created by admin on 2016/12/13.
 */
public class TwoCurveView extends View {private float startX,startY;
    private float endX,endY ;
    private float contorlX = 200,contorlY = 60;//默认值
    private Paint paint;
    private float t;
    private Path path;
    public TwoCurveView(Context context, AttributeSet attrs) {super(context, attrs);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        startX = 60;
        startY = 350;
        endX = 450;
        endY = 350;
        path = new Path();
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        path.reset();
        path.moveTo(startX,startY);
        path.quadTo(contorlX,contorlY,endX,endY);
        canvas.drawPath(path,paint);
    }@Override
    public boolean onTouchEvent(MotionEvent event) {if(event.getAction()==MotionEvent.ACTION_MOVE){contorlX = event.getX();
            contorlY = event.getY();
            invalidate();
        }return true;
    }
}

效果:

可能在看别的博客会发现别人有演示的动画,这样看起来更直观点,比如这种图:

这个我当时想自己通过绘制出来的,但是有些地方没想明白,后来请教了石宗银大神,在这感谢石神的教导,在我心中他是一位智者,一位受人尊敬的leader,好了不吹了,再吹他衣服都要吹没了

首先p0p1,p1p2这二条直线绘制出来没问题的,红色的轨迹也好绘制,根据二阶曲线的公式,你可以把这些轨迹看成无数个点构成,所以你只要绘制无数个点就行了,当时想不明白的是哪绿色的辅助线不怎么绘制出来,根据这个思路把代码实现下:

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.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by admin on 2016/12/13.
 */
public class TwoCurveView extends View {private float startX,startY;
    private float endX,endY ;
    private float contorlX = 200,contorlY = 60;//默认值
    private Paint paint;
    private float t;
    private Path path;
    private List<PointF> points;//存储曲线上运动的点
    public TwoCurveView(Context context, AttributeSet attrs) {super(context, attrs);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        startX = 60;
        startY = 350;
        endX = 450;
        endY = 350;
        path = new Path();
        points = new ArrayList<>();
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        if(t>=1.0f){t=1.0f;
        }//绘制2根线  起点-控制点  控制点-终点
        paint.setColor(Color.parseColor("#e5e5e5"));
        canvas.drawLine(startX,startY,contorlX,contorlY,paint);
        canvas.drawLine(contorlX,contorlY,endX,endY,paint);
        //
        float p3x = (1 - t) * startX+ t* contorlX;
        float p3y = (1 - t) *startY + t * contorlY;
        float p4x = (1 - t) * contorlX + t * endX;
        float p4y = (1 - t) * contorlY + t * endY;
        paint.setColor(Color.GREEN);
        //这是绘制辅助线说明轨迹的运动情况 轨迹的运动情况
        canvas.drawLine(p3x, p3y, p4x, p4y, paint);
        //绘制曲线轨迹
        float p5x = (1 - t) * p3x + t * p4x;
        float p5y = (1 - t) * p3y + t * p4y;
        points.add(new PointF(p5x, p5y));
        paint.setColor(Color.RED);
        PointF ps, pe;
        for (int i = 1; i < points.size(); i++) {//其实这个二阶曲线就是由无数个点构成,然后把前后2个点构成一条直线
            ps = points.get(i - 1);
            pe = points.get(i);
            canvas.drawLine(ps.x, ps.y, pe.x, pe.y, paint);//绘制贝塞尔在时间0到1内运动轨迹
        }postDelayed(new Runnable() {@Override
            public void run() {t+=0.01;
                invalidate();
            }},50);
        if(t==1.0f){//绘制曲线轨迹曲线
            path.reset();//记得一定要重置path
            path.moveTo(startX,startY);
            path.quadTo(contorlX,contorlY,endX,endY);
            canvas.drawPath(path,paint);
        }}@Override
    public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:contorlX = event.getX();
                contorlY = event.getY();
                t = 0;
                points.clear();
                invalidate();
                break;
        }return true;
    }
}

效果:

下面画图分析这个运动轨迹

现在讲下三阶曲线,它是由2个控制点,一个起点,一个终点构成的,api:

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

参数说明:

(x,y1)是控制点1

(x2,y2)是控制点2

(x3,y3)是终点

现在和上面一样,绘制一个动态的三阶曲线运动轨迹:

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.PointF;
import android.util.AttributeSet;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by admin on 2016/12/13.
 */
public class ThreeCurveView extends View {private float startX,startY;
    private float endX,endY ;
    private float contorlX1 = 90,contorlY1 = 60;//默认值
    private float contorlX2 = 400,contorlY2 = 60;//默认值
    private Paint paint;
    private float t;
    private Path path;
    private List<PointF> points;//存储曲线上运动的点
    public ThreeCurveView(Context context, AttributeSet attrs) {super(context, attrs);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        startX = 60;
        startY = 350;
        endX = 450;
        endY = 350;
        path = new Path();
        points = new ArrayList<>();
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        if(t>=1.0f){t=1.0f;
        }//绘制线 起点-控制点1  控制点1-控制点2  控制点2-终点
        paint.setStrokeWidth(4);
        paint.setColor(Color.parseColor("#e5e5e5"));
        canvas.drawLine(startX,startY,contorlX1,contorlY1,paint);
        canvas.drawLine(contorlX1,contorlY1,contorlX2,contorlY2,paint);
        canvas.drawLine(contorlX2,contorlY2,endX,endY,paint);
        //绘制轨迹直线
        float p3x = (1 - t) * startX+ t* contorlX1;
        float p3y = (1 - t) *startY + t * contorlY1;
        float p4x = (1 - t) * contorlX1 + t * contorlX2;
        float p4y = (1 - t) * contorlY1 + t * contorlY2;
        float p5x = (1 - t) * contorlX1+ t* contorlX2;
        float p5y = (1 - t) *contorlY1 + t * contorlY2;
        float p6x = (1 - t) * contorlX2 + t * endX;
        float p6y = (1 - t) * contorlY2 + t * endY;

        float pc7x = (1 - t) * p3x + t * p4x;
        float pc7y = (1 - t) * p3y + t * p4y;

        float pc8x = (1 - t) * p5x + t * p6x;
        float pc8y = (1 - t) * p5y + t * p6y;
        paint.setColor(Color.GREEN);
        //绘制曲线运动轨迹
        canvas.drawLine(p3x, p3y, p4x, p4y, paint);
        canvas.drawLine(p5x, p5y, p6x, p6y, paint);
        paint.setColor(Color.BLUE);
        //绘制辅助线
        canvas.drawLine(pc7x, pc7y, pc8x, pc8y, paint);

        float p9x = (1 - t) * pc7x + t * pc8x;
        float p9y = (1 - t) * pc7y + t * pc8y;
        points.add(new PointF(p9x, p9y));
        paint.setColor(Color.RED);
        PointF ps, pe;
        for (int i = 1; i < points.size(); i++) {//其实这个二阶曲线就是由无数个点构成,然后把前后2个点构成一条直线
            ps = points.get(i - 1);
            pe = points.get(i);
            canvas.drawLine(ps.x, ps.y, pe.x, pe.y, paint);//绘制贝塞尔在时间0到1内曲线运动轨迹
        }paint.setColor(Color.parseColor("#e5e5e5"));
        paint.setStrokeWidth(6);
        paint.setColor(Color.BLUE);
        canvas.drawPoint(contorlX1,contorlY1,paint);
        canvas.drawPoint(contorlX2,contorlY2,paint);
        path.reset();
        if(t==1.0f){path.moveTo(startX,startY);
            path.cubicTo(contorlX1,contorlY1,contorlX2,contorlY2,endX,endY);
            canvas.drawPath(path,paint);
        }postDelayed(new Runnable() {@Override
            public void run() {t+=0.01;
                invalidate();
            }},50);
    }
}

效果:

ok,大于3阶曲线,水平有限,写不出来,实际也很少用到,写的吐血!

现在写个demo玩下:

第一个例子就是在画笔上写文字了,不是通过drawText...()去绘制的,很简单

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.MotionEvent;
import android.view.View;
/**
 * Created by admin on 2016/12/13.
 */
public class DemoCurveView extends View {private Path path;
    private Paint paint;
    public DemoCurveView(Context context, AttributeSet attrs) {super(context, attrs);
        initPaint();
    }private void initPaint() {paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.GRAY);
        path = new Path();
    }@Override
    public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:path.moveTo(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:path.lineTo(event.getX(),event.getY());
                invalidate();
                break;
        }return true;
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        canvas.drawPath(path,paint);
    }
}

效果:

另外一种实现方式:就是通过我们所学的二阶曲线,这个关键一点就是控制点是不断变化的,是以你上一个点为控制点,所以只要记录上一个点为控制点就ok

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.MotionEvent;
import android.view.View;
/**
 * Created by admin on 2016/12/13.
 */
public class DemoCurveView extends View {private Path path;
    private Paint paint;
    private float contorlx1,contorly1;//控制点
    public DemoCurveView(Context context, AttributeSet attrs) {super(context, attrs);
        initPaint();
    }private void initPaint() {paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.GRAY);
        path = new Path();
    }@Override
    public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:path.moveTo(event.getX(),event.getY());
                contorlx1 = event.getX();
                contorly1 = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:float endX = event.getX();
                float endY = event.getY();
                path.quadTo(contorlx1,contorly1,endX,endY);
                contorlx1 = endX;
                contorly1 = endY;
                invalidate();
                break;
        }return true;
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        canvas.drawPath(path,paint);
    }
}

效果:

就写到这里把,太累,龙体欠佳啊!

android path基本使用以及贝塞尔曲线入门相关推荐

  1. Android Studio Canvas 实现鼠标贝塞尔曲线拖尾特效

    Android Studio Canvas 实现鼠标贝塞尔曲线拖尾特效 特效预览图 什么是贝塞尔曲线? 百度百科: ​ 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图 ...

  2. Android Studio Canvas 实现鼠标贝塞尔曲线拖尾特效(富文本编辑器)

    特效预览图 什么是贝塞尔曲线? 百度百科: 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段 ...

  3. SVG Path(四)贝塞尔曲线命令

    贝塞尔曲线示例,分别为 1.2.3.4 次贝塞尔曲线. 二次贝塞尔曲线: 三次贝塞尔曲线: M x0 y0 C x1 y1 x2 y2 x y (x0, y0):起始点 (x1, y1):起始控制点 ...

  4. Path绘制动态的贝塞尔曲线、PathMeasure来绘制path动画

    上一篇的波浪曲线是左右重复平移,这次是每一帧绘制一条线,组成上下浮动的曲线,下面是效果图 public WaveView(Context context, @Nullable AttributeSet ...

  5. Android 贝塞尔曲线实战之网易云音乐鲸云特效,2021程序员进阶宝典

    一阶这个比较简单,因为没有在网上找到可以直接输入数学公式的工具,就手工推导了下. ![在这里插入图片描述](https://img- <Android学习笔记总结+最新移动架构视频+大厂安卓面试 ...

  6. Android 贝塞尔曲线实战之网易云音乐鲸云特效,apm性能监控系统

    小说阅读 APP 的翻页效果. 简介 ===================================================================== 在开始实战之前,我们还 ...

  7. Android 贝塞尔曲线实战之网易云音乐鲸云特效

    作者:哈哈将 -个推 Android 高级开发工程师 前言 APP开发市场已经告别"野蛮生长"时代,人们不再满足于APP外形创新,而将目光转向全方面的用户体验上.在这过程中,动效化 ...

  8. Android 贝塞尔曲线实现QQ拖拽清除效果

    纯属好奇心驱动写的一个学习性Demo,效果如下: 这个小功能最重要的点在于起始点和触摸点之间的连接线绘制,它并不是一条单纯的直线,而是中间细两头粗的一条不规则的Path,而这个中间向内弯曲的效果正是一 ...

  9. 【Android UI】贝塞尔曲线 ⑦ ( 使用 德卡斯特里奥算法 公式计算的 方法绘制三阶贝塞尔曲线示例 )

    文章目录 一.使用 德卡斯特里奥算法 公式计算的 方法绘制三阶贝塞尔曲线 二.代码示例 贝塞尔曲线参考 : https://github.com/venshine/BezierMaker 一.使用 德 ...

最新文章

  1. Python的控制语句1
  2. 双向非循环递增链表——插入,删除,清空
  3. 织梦添加幻灯片的方法
  4. 集群scan_扫描k8s集群中的漏洞
  5. XSS盗COOKIE
  6. 第十届蓝桥杯java B组—试题C 数列求值
  7. (011)XHTML文档之列表
  8. 配置Apache虚拟机
  9. 概率论与数理统计-课程感悟
  10. Autodesk CAD帮助文档 DXF 图层使用
  11. Probabilistic Road Map
  12. 两个服务器微信消息模板发不出去,小程序模板消息调用send大部分情况下发送不出去,但有时又可以发送,什么情况?...
  13. 让人寒心,义工丛飞资助的是一群白眼狼?
  14. 【面试】前端面试之开发性能篇
  15. android 程序a启动程序b的权限,android app微信分享
  16. 目标检测系列:高分辨率表示HRNetV1、HRNetV2/V2p
  17. DaisyDisk for mac(磁盘清理软件)中文版
  18. matlab绘制四棱台,Auto-CAD2016斜截四棱台的画法.ppt
  19. 北大美女王婷婷辞去公司副总职务创业养狗(图)
  20. eclipse介绍,环境配置,mysql安装

热门文章

  1. [opencv 从零开始 5 ] python 将图片加密解密,图片加隐藏水印,提取水印。
  2. access如何保存小数点后_搞笑沙雕表情包合集,顺便教会你保存后如何转换成微信表情包...
  3. Android Activity的title的设置
  4. 网易严选库存中心设计实践
  5. 2021年中国干法啤酒花系统市场趋势报告、技术动态创新及2027年市场预测
  6. 微信小程序之获取用户信息(流程+2种方法)
  7. python数组独立复制
  8. 举例解释一下MySQL的表锁和行锁
  9. 入手评测 华为Watch3和Watch3 Pro的区别
  10. noip2004初赛-三角形内切圆的面积