Path可以按照路径画出很多效果,而使用pathMeasure可以对path进行测量,或者找到某个点具体位置等。
使用pathMeasure实现如下效果
思路:
1.首先使用path画出桃心路径
2.接着使用pathMeasure获取该点的Matrix
3.将图片画到对应的matrix上,再使用属性动画不断更新视图
画出桃心路径
// 起始点
private static final int[] START_POINT = new int[] {
300, 270
};
// 爱心下端点
private static final int[] BOTTOM_POINT = new int[] {
300, 400
};
// 左侧控制点
private static final int[] LEFT_CONTROL_POINT = new int[] {
450, 200
};
// 右侧控制点
private static final int[] RIGHT_CONTROL_POINT = new int[] {
150, 200
};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
canvas.translate(0,200);
mPath.moveTo(START_POINT[0], START_POINT[1]);
mPath.quadTo(RIGHT_CONTROL_POINT[0], RIGHT_CONTROL_POINT[1], BOTTOM_POINT[0],
BOTTOM_POINT[1]);
mPath.quadTo(LEFT_CONTROL_POINT[0], LEFT_CONTROL_POINT[1], START_POINT[0], START_POINT[1]);
mPathMeasure.setPath(mPath,true);
canvas.drawPath(mPath,mPaint);
}
这些点直接从demo中找来的,可以去画贝塞尔曲线的网站模拟一下
接着画箭头图片,其实也很简单
float length = mPathMeasure.getLength();
mPathMeasure.getMatrix(length*mFraction,mMatrix,TANGENT_MATRIX_FLAG|POSITION_MATRIX_FLAG);
mMatrix.preTranslate(-androidBitmap.getWidth()/2,-androidBitmap.getHeight()/2);
canvas.drawBitmap(androidBitmap,mMatrix,mPaint);
首先使用pathmeasure获取路径该点的Martix,然后前移动图片的宽度和高度,就可以直接使用了,这种方式少了很多计算。
完整代码
public class PathArray extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private Bitmap androidBitmap;
private float mFraction=0f;
private Matrix mMatrix;
// 起始点
private static final int[] START_POINT = new int[] {
300, 270
};
// 爱心下端点
private static final int[] BOTTOM_POINT = new int[] {
300, 400
};
// 左侧控制点
private static final int[] LEFT_CONTROL_POINT = new int[] {
450, 200
};
// 右侧控制点
private static final int[] RIGHT_CONTROL_POINT = new int[] {
150, 200
};
public PathArray(Context context) {
super(context);
init();
}
private void init() {
mPath=new Path();
mPaint=new Paint();
mMatrix=new Matrix();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPathMeasure=new PathMeasure();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=16;
androidBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ic_array,options);
}
public PathArray(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
mMatrix.reset();
canvas.translate(0,200);
mPath.moveTo(START_POINT[0], START_POINT[1]);
mPath.quadTo(RIGHT_CONTROL_POINT[0], RIGHT_CONTROL_POINT[1], BOTTOM_POINT[0],
BOTTOM_POINT[1]);
mPath.quadTo(LEFT_CONTROL_POINT[0], LEFT_CONTROL_POINT[1], START_POINT[0], START_POINT[1]);
mPathMeasure.setPath(mPath,true);
canvas.drawPath(mPath,mPaint);
float length = mPathMeasure.getLength();
mPathMeasure.getMatrix(length*mFraction,mMatrix,TANGENT_MATRIX_FLAG|POSITION_MATRIX_FLAG);
mMatrix.preTranslate(-androidBitmap.getWidth()/2,-androidBitmap.getHeight()/2);
canvas.drawBitmap(androidBitmap,mMatrix,mPaint);
}
public void startAnim(){
ValueAnimator animator=ValueAnimator.ofFloat(0,1);
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mFraction = (float) animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
}