Path, 轨迹,路径。Path可以沿着多个点绘制一条路径, 在Canvas中可以根据Path绘制不同的图形。
Path
我们在使用Path绘制路径,一般要使用到以下几个方法:
moveTo(float x, float y):
移动到(x, y)坐标点。绘制路径时,路径的第一个点一般我们通过moveTo()来决定,否则默认为(0, 0)点。
lineTo(float x, float y):
从当前点绘制直线到(x, y)点。这个与moveTo()不同,moveTo()是指跳转到(x, y)点,而不绘制连线。
close():
将路径封闭。举例来说,我们绘制一个三角形,三角形的三个点是(0, 0,),(100, 0),(0, 100)我们使用lineTo将(0, 0,),(100, 0)连接,(100, 0),(0, 100)连接,这样还差(0, 0,),(0, 100)之间的连线,这时我们可以直接调用close()方法,这样就会直接将图形封闭构成三角形。
quadTo(float x1, float y1, float x2, float y2):
绘制贝塞尔曲线,贝塞尔曲线是由三个点控制的:起始点,终止点,控制点。在该方法中,前两个参数是控制点的坐标,后两个参数是终止点坐标。
Path中我们可以通过点来绘制路径也可以通过addXXX()方法来绘制,Path中给我们提供了很多这样的方法来添加不同的路径:
方法 | 用途 |
---|---|
addArc(RectF oval, float startAngle, float sweepAngle) | 添加圆弧轨迹 |
addCircle(float x, float y, float radius, Path.Direction dir) | 添加圆形轨迹 |
addOval(float left, float top, float right, float bottom, Path.Direction dir) | 添加椭圆轨迹 |
addRect(float left, float top, float right, float bottom, Path.Direction dir) | 添加矩形轨迹 |
addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir) | 添加椭圆角矩形轨迹 |
以上方法与Canvas构建圆形,弧形,椭圆等图形方法的使用是差不多的,我们这里不再赘述。下面来几个小练习,练习下Path的使用。
Path的使用
绘制三角形
public class MyPathView extends View {
private int width;//设置高
private int height;//设置高
private Path mPath;
private Paint mPaint;
public MyPathView(Context context) {
super(context);
}
public MyPathView(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化path
mPath = new Path();
//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗锯齿
mPaint.setColor(Color.LTGRAY);
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);//非填充
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//设置宽和高
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画三角形
mPath.moveTo(100, 100);
mPath.lineTo(0, 200);
mPath.lineTo(200, 200);
mPath.close();
canvas.drawPath(mPath, mPaint);
}
}
书写文字沿圆形轨迹
public class MyPathView extends View {
private int width;//设置高
private int height;//设置高
private Path mPath;
private Paint mPaintCircle;
public MyPathView(Context context) {
super(context);
}
public MyPathView(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化path
mPath = new Path();
//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗锯齿
mPaint.setTextSize(30);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);//非填充
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//设置宽和高
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画圆形
mPath.addCircle(width/2, height/2, 300, Path.Direction.CW);
mPath.close();
canvas.drawPath(mPath, mPaint);
canvas.drawTextOnPath("我要沿着这个圆写一些文字", mPath,0,0, mPaint );
}
}
绘制贝塞尔曲线
public class MyPathView extends View {
private int width;//设置高
private int height;//设置高
private Path mPath;
private Paint mPaint;
private Paint mPaintPoint;
public MyPathView(Context context) {
super(context);
}
public MyPathView(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化path
mPath = new Path();
//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗锯齿
mPaint.setTextSize(30);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);//非填充
//初始化画点的画笔
mPaintPoint = new Paint();
mPaintPoint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaintPoint.setStrokeWidth(10);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//设置宽和高
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.moveTo(100, 100);//确定贝塞尔曲线的第一个点
mPath.quadTo(50, 400, 500, 400);//前两个参数确定控制点, 后两个参数确定结束点
//绘制出起始点,终止点,以及控制点
canvas.drawPoint(100, 100, mPaintPoint);
canvas.drawPoint(50,400, mPaintPoint);
canvas.drawPoint(500, 400, mPaintPoint);
canvas.drawPath(mPath,mPaint);
}
}
Path路径还可以绘制更多各式各样的路径,这里不再一一练习。下面绘制一个波动的Path曲线。
绘制波动的Path曲线
绘制波动的曲线,要是画面动起来就需要不断地调用onDraw方法绘制界面。但是onDraw是UI主线程不断调用重绘界面的,因此我们需要使用到Handler,通过发送一个消息给Handler对象,让Handler对象在每一秒重绘一次MyPathView控件。这里重绘不能调用onDraw()方法额,而要调用的是invalidate()方法,invalidate()方法中调用了onDraw()方法。
public class MyPathView extends View {
private int width;//设置高
private int height;//设置高
private Path mPath;
private Paint mPaint;
private Paint mPaintCircle;
private int count = 0;
private static final int NEED_INVALIDATE = 0X6666;
//操作UI主线程
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case NEED_INVALIDATE:
//更新时间
count += 5;
if (count > 80) {
count = 0;
}
invalidate();
sendEmptyMessageDelayed(NEED_INVALIDATE, 50);
break;
}
}
};
public MyPathView(Context context) {
super(context);
}
public MyPathView(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化path
mPath = new Path();
//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗锯齿
mPaint.setTextSize(30);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setStyle(Paint.Style.STROKE);//非填充
//初始化画点的画笔
mPaintCircle = new Paint();
mPaintCircle.setAntiAlias(true);
mPaintCircle.setColor(Color.GRAY);
mPaintCircle.setStyle(Paint.Style.STROKE);
mPaintCircle.setStrokeWidth(10);
handler.sendEmptyMessageDelayed(NEED_INVALIDATE, 50);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//设置宽和高
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制波浪形曲线
mPath.reset();
mPath.moveTo(count, height / 2);
for (int i = 0; i < 10; i++) {
mPath.rQuadTo(20, 5, 40, 0);//rQuadTo()方法是以当前点为起始点,将其视为(0,0)点绘制。这里也就是将
mPath.rQuadTo(20, -5, 40, 0);
}
canvas.drawPath(mPath, mPaint);
canvas.drawCircle(width / 2, height / 2, 50, mPaintCircle);
}
}
我们首先通过循环得到了贝塞尔曲线,这里得到贝塞尔曲线是通过rQuadTo()方法,这个方法,是将当前的点视为原点(0, 0),通过相对原点来绘制的曲线。绘制好贝塞尔曲线后,我们通过使用Handler通过count不断地更新起始点move(count, width),使得曲线看起来是移动的。