上边是效果图
上边是依据两种方式实现的,先说地一个效果的实现
要实现地一个效果,肯定需要掌握path,patnMeasure,valueAnimator这里跟自定义view关系不是很大
思路
1 先实现一个静态的效果(用path来绘制) (为什么使用path呢?因为使用path我们可以用pathMeasure来测量出path没一个点的坐标)
2 然后用pathMeasure来测量path然后结合valueAnimator来获取path路径的没一个坐标,然后再更新界面就可以得到效果
上代码,代码比较短,注释也很清楚
public class PathMeasureTest extends View {
//画笔
private Paint mPaint;
//隐形的路径
private Path mPath;
//绘制用户看到的路径
private Path mSecondPath;
//路径测量
private PathMeasure mPathMeasure;
//宽度和高度
private float width;
private float height;
//获取当前线段的位置 pos[0]为x轴 pos[1]为y轴
private float[] pos = new float[2];
public PathMeasureTest(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setStrokeWidth(10);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPath = new Path();
mPathMeasure = new PathMeasure();
mSecondPath = new Path();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.moveTo(width / 2, height / 2);
mPath.rLineTo(40, 40);
mPath.rLineTo(90, -60);
mPaint.setColor(Color.RED);
mSecondPath.lineTo(pos[0], pos[1]);
canvas.drawPath(mSecondPath, mPaint);
}
public void startAnim() {
mSecondPath.reset();
mPathMeasure.setPath(mPath, false);
mSecondPath.moveTo(width / 2, height / 2);
final ValueAnimator anim = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
anim.setDuration(300);
anim.setInterpolator(new LinearInterpolator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//获取位置
mPathMeasure.getPosTan(value, pos, null);
postInvalidate();
}
});
anim.start();
}
}
继续说我们第二种的实现,使用到了pathMeasure的一个方法pathMeasure.getSegment这个方法,具体介绍请看这篇博客
http://blog.csdn.net/u013831257/article/details/51565591
pathMeasure.getSegment( float startD, float stopD, Path dst, boolean startWithMoveTo);我们说一说这个方法有什么用?传入的参数分别是什么
1)这个方法的字面意思是得到一个段落(得到一个路径的一部分),你可能会问得到一部分就得到呗,跟我们说的这个有什么关系呢?得到一部分之后,我们再结合属性动画就可以慢慢绘制出来效果
2)传入的参数分别是开始位置,结束位置,把获取到的path赋值到一个新的path下(dst),起始点是否使用moveTo.
public class PathMeasureSegmentTest extends View {
private Paint mPaint;
private Path mPath;
private PathMeasure mPathMeasure;
private Path dstPath;
public PathMeasureSegmentTest(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(10);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPath = new Path();
mPathMeasure = new PathMeasure();
dstPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.moveTo(100, 100);
mPath.rLineTo(100, 100);
mPath.moveTo(200, 100);
mPath.rLineTo(-100, 100);
mPaint.setColor(Color.RED);
canvas.drawPath(dstPath, mPaint);
}
private float lenght;
private boolean isNextFlag;
public void startAnim() {
//这里每次都重置,因为每次点击就都可以看到效果
dstPath.rewind();
isNextFlag = true;
mPathMeasure.setPath(mPath, false);
lenght = mPathMeasure.getLength();
final ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.setDuration(200);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//19版本之前要想看到效果最简单的方法就是使用rLineTo(0,0)
dstPath.rLineTo(0, 0);
//获取一个段落
mPathMeasure.getSegment(0, lenght * value, dstPath, true);
invalidate();
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (isNextFlag) {
//绘制完一条线之后,再绘制另外一条线
mPathMeasure.nextContour();
lenght = mPathMeasure.getLength();
mValueAnimator.start();
isNextFlag = false;
}
}
});
mValueAnimator.start();
}
}
使用方法是:在布局文件中声明,然后调用每个view中的startAnim()方法