Android基础之Path类的使用
我们知道Android中Canvas类对象可以进行绘制事物,里面有一个方法为canvas.drawPath方法,这个方法就是用来绘制我们的自定义Path对象。Path对象很有用,我们可以绘制一些特殊的动画效果,文字吸附效果等等。所以我们需要来学习下Path对象的使用。
Path对象的方法
一、构造函数
1、无参构造函数
/**
* Create an empty path
*/
public Path() {
mNativePath = init1();
}
创建一个空的Path对象。
/**
* 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) {
long valNative = 0;
if (src != null) {
valNative = src.mNativePath;
isSimplePath = src.isSimplePath;
if (src.rects != null) {
rects = new Region(src.rects);
}
}
mNativePath = init2(valNative);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
创建一个将非空的含有src的Path对象。
二、成员函数
1、 public void moveTo(float x, float y)
移动绘制的起点,从点(x,y)点开始进行绘制。
2、 public void lineTo(float x, float y)
连接起始点与点(x,y)的直线,如果没有使用moveTo则起始点默认为(0,0)。
实例1:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.lineTo(300,300);
canvas.drawPath(mPath,mPaint);
}
我们绘制点(0,0)与点(300,300)之间的直线。效果图:
![lineto](https://img-blog.csdn.net/20151006144827299)
实例2:我们在lineTo之前添加MoveTo方法。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.moveTo(100,100);
mPath.lineTo(300,300);
canvas.drawPath(mPath,mPaint);
}
我们将起点移动到点(100,100)绘制点与点(300,300)之间的线。效果图如图:
![moveto](https://img-blog.csdn.net/20151006144856558)
3、public void rMoveTo(float dx, float dy)
在绘制线的终点的基础上移动(dx,dy)得到新的起始点。
实例3:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
mPath.lineTo(100,100)
mPath.rMoveTo(50,50)
mPath.lineTo(300,300)
canvas.drawPath(mPath,mPaint)
}
我们先进行点(0,0)与点(100,100)之间连线,然后通过rMoveTo方法移动(50,50)个距离,即现在的起点是(150,150),然后绘制到(300,300)之间的直线。
效果图:
![rmoveto](https://img-blog.csdn.net/20151006144932507)
4、public void rLineTo(float dx, float dy)
与lineTo功能类似,但是是在上个线的终点基础上进行绘制,不是lineTo的从(0,0)开始。
实例4:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.lineTo(100,50);
mPath.rLineTo(200,300);
canvas.drawPath(mPath,mPaint);
}
我们先绘制(0,0)到(100,50)之间的线,然后在(100,50)的起点基础上绘制(300,350)之间的线。
效果图:
![rlineto](https://img-blog.csdn.net/20151006144958717)
5、public void quadTo(float x1, float y1, float x2, float y2)
根据两个控制点绘制贝塞尔曲线。如果没有使用moveTo指定起点,起点默认为(0,0),即(0,0)到(x1,y1)之间绘制贝塞尔曲线,(x1,y1)到(x2,y2)之间绘制贝塞尔曲线。
实例5:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.quadTo(100,50,300,500);
canvas.drawPath(mPath,mPaint);
}
效果图:
![quadTo](https://img-blog.csdn.net/20151006145026803)
6、 public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3)
通过三个控制点绘制贝塞尔曲线。
实例代码6:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.lineTo(100,50);
mPath.lineTo(200, 300);
mPath.lineTo(400, 220);
canvas.drawPath(mPath, mPaint);
mPath = new Path();
mPath.cubicTo(100, 50, 200, 300, 400, 220);
canvas.drawPath(mPath,mPaint);
}
![cubicTo](https://img-blog.csdn.net/20151006145052286)
实例7:更改起点
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
//为了增强效果对比,我们绘制出三个控制点之间对应的直线
mPath.moveTo(200,100)
mPath.lineTo(100,50)
mPath.lineTo(200, 300)
mPath.lineTo(400, 220)
canvas.drawPath(mPath, mPaint)
mPath = new Path()
//绘制贝塞尔曲线
mPath.moveTo(200,100)
mPath.cubicTo(100, 50, 200, 300, 400, 220)
canvas.drawPath(mPath,mPaint)
}
![moveToAndcubicTo](https://img-blog.csdn.net/20151006145114371)
7、public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
方法同quadTo,主要不同是这里的dx、dy表示的是坐标的差值,类似上面的rlineTo,相对上一个点的dx、dy的计算后的终点。但是注意此时的dx、dy都是相对于起点,即二者的起点都是相同的,(dx2,dy2)不是相对于(dx1,dy1)。
实例8:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
mPath.rLineTo(100,100);
mPath.lineTo(400, 220);
canvas.drawPath(mPath, mPaint);
mPath = new Path();
mPath.rQuadTo(100, 100,400, 220);
canvas.drawPath(mPath,mPaint);
}
效果图:
最终的终点是(400,220),所以也印证了dx2、dy2与dx1、dy1有相同的起点。
8、public void rCubicTo(float x1, float y1, float x2, float y2,
float x3, float y3)效果与上相同,就不演示了。
9、public void arcTo(RectF oval, float startAngle, float sweepAngle)
用于绘制圆弧。
public void addRect(float left, float top, float right, float bottom, Direction dir)添加矩形
实例9:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
RectF rectF = new RectF(100,100,300,300)
mPath.addRect(rectF, Path.Direction.CW)
mPath.addArc(rectF,0,360)
canvas.drawPath(mPath,mPaint)
}
效果图:
![arc](https://img-blog.csdn.net/20151006145223794)
其它几个方法类似。
10、 public void addOval(RectF oval, Direction dir)
添加一个闭环的圆环路径。
实例10:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
RectF rectF = new RectF(100,100,400,300)
mPath.addRect(rectF, Path.Direction.CW)
mPath.addOval(rectF,Path.Direction.CW)
canvas.drawPath(mPath,mPaint)
}
效果图:
![oval](https://img-blog.csdn.net/20151006145246725)
11、public void addCircle(float x, float y, float radius, Direction dir)
添加一个圆形路径。
实例11:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
mPath.addCircle(200,200,100,Path.Direction.CW)
canvas.drawPath(mPath,mPaint)
}
效果图:
![cicle](https://img-blog.csdn.net/20151006145313126)
12、public void addRoundRect(RectF rect, float rx, float ry, Direction dir)
添加圆角矩形路径。
- @param rx The x-radius of the rounded corners on the round-rectangle
- @param ry The y-radius of the rounded corners on the round-rectangle
- @param dir The direction to wind the round-rectangle’s contour
实例12:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.parseColor("#ff0000"));
RectF rectF = new RectF(100,100,400,300);
mPath.addRoundRect(rectF,20,20, Path.Direction.CW);
canvas.drawPath(mPath,mPaint);
}
效果图:
![RoundrectF](https://img-blog.csdn.net/20151006145358011)
13、public void offset(float dx, float dy, Path dst)
public void offset(float dx, float dy)
通过dx、dy进行移动path,如果dst为null,则修改原路径,即src
14、 public void reset(),清空path路径中的信息。
15、 public void rewind(),rewind当前path,清除掉所有直线,曲线,但是保留它内部的数据结构,以便更好的重新使用
补充:
1、Path.Direction
用来指定添加到path中的模型(比如方形,椭圆)的闭合方向,有两个值
2、FillType表示填充模式,它的填充模式和Paint的不同,它有四个枚举值。Inverse就是去反之意。
- FillType.WINDING,默认值,当两个图形香蕉,正常相交情况显示
- FillType.EVEN_ODD,取path所在并不相交的区域
- FillType.INVERSE_WINDING,取path的外部区域
- FillType.INVERSE_EVEN_ODD:取path外部和相交区域
实例:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
mPaint.setColor(Color.parseColor("#ff0000"))
mPath.addRect(100, 100, 300, 300, Path.Direction.CW)
mPath.addCircle(300, 300, 100, Path.Direction.CW)
mPath.setFillType(Path.FillType.WINDING)
canvas.drawPath(mPath,mPaint)
}
(1)FillType.WINDING
(2)FillType.EVEN_ODD
(3)INVERSE_EVEN_ODD
(4)FillType.INVERSE_WINDING
![FillType.INVERSE_WINDING](https://img-blog.csdn.net/20151006145523151)
至此,所有的Path的使用基本介绍完毕。下面我们继续我们前进的脚步,学习与Path对象息息相关的一个对象——PathMeasure。见名思意,该类的功能就是用来测量Path对象的。
PathMeasure
构造方法
(1)、无参构造方法
public PathMeasure() {
mPath = null;
native_instance = native_create(0, false);
}
(2)有参构造方法
public PathMeasure(Path path, boolean forceClosed) {
mPath = path;
native_instance = native_create(path != null ? path.ni() : 0,
forceClosed);
}
一般方法介绍
(1)、public void setPath(Path path, boolean forceClosed) ,设置测量的path对象
(2)、public float getLength() ,测量path的长度
(3)、 public boolean getPosTan(float distance, float pos[], float tan[]),根据distance获取对应的点坐标
(4)、public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo),返回指定distance之间的path段。
注意:无论多复杂,PathMeasure也是将所有path中的路径看成一个直线,取位置,然后计算出对应的坐标。
下面我们做个小demo来练习下上面的知识点。
效果图:
![result](https://img-blog.csdn.net/20151006145845522)
最后贴上源码:
/**
* Created by dsw on 2015/10/5.
*/
public class MyLine extends View {
private Paint mPaint;
private Path mPath;
private PathMeasure pathMeasure;
private int mLenght;
private int mCurrentPath;
private float[] currentPosition;
private Bitmap bitmap;
private float pointX[] = new float[5];
private float pointY[] = new float[5];
public MyLine(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPath = new Path();
currentPosition = new float[2];
bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.star);
mPaint.setColor(Color.parseColor("#ff0000"));
mPaint.setStyle(Paint.Style.STROKE);
pointX[0] = 113.5f;pointY[0] =150f;
pointX[1] = 286.5f;pointY[1] = 150f;
pointX[2] = 150f;pointY[2] = 286.5f;
pointX[3] = 200f;pointY[3] = 100f;
pointX[4] = 250f;pointY[4] = 286.5f;
mPath.moveTo(pointX[0], pointY[0]);
for(int i=1;i<5;i++) {
mPath.lineTo(pointX[i],pointY[i]);
}
mPath.lineTo(pointX[0],pointY[0]);
pathMeasure = new PathMeasure();
pathMeasure.setPath(mPath,true);
mLenght = (int) pathMeasure.getLength();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
if(mCurrentPath == 0 && currentPosition[0]==0 && currentPosition[1]==0){
startAnimator();
}else{
canvas.drawBitmap(bitmap,currentPosition[0]-bitmap.getWidth()/2,
currentPosition[1]-bitmap.getHeight()/2,mPaint);
}
}
/**
* 计算每次的位置
*/
private void startAnimator(){
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mLenght);
valueAnimator.setDuration(5000);
valueAnimator.setRepeatCount(-1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentPath = (int) animation.getAnimatedValue();
pathMeasure.getPosTan(mCurrentPath, currentPosition, null);
invalidate();
}
});
valueAnimator.start();
}
}
转载:http://blog.csdn.net/mr_dsw/article/details/48931515