路径动画
1.1、初始化
初始化后设置是否闭合:
Path path = new Path();
PathMeasure pathMeasure1 = new PathMeasure();
/**
* 路径是否闭合 forceClosed
*/
pathMeasure1.setPath(path, true);
或者直接构造函数初始化:
PathMeasure pathMeasure2 = new PathMeasure(path, true);
1.2、获取路径长度
/**
* 路径长度,测量的是当前路径状态的长度,如果forceClosed为true,则不论路径是否闭合,测量的都是路径的闭合长度。
* 获取到的长度是当前曲线的长度。
*/
System.out.println(pathMeasure1.getLength());
1.3、判断路径是否闭合
/**
* 判断路径是否闭合
*/
System.out.println(pathMeasure1.isClosed());
1.4、跳转到路径的下一条曲线
/**
* 跳转到下一条曲线,true表示跳转成功,false表示跳转失败。
*
*/
System.out.println(pathMeasure1.nextContour());
1.5、截取路径的某个片段
/**
* 截取整个Path中startD到stopD的某个片段,如果不在范围则返回false,截取后添加Path到dst中。
* startWithMoveTo:如果为true,则被截取的Path片段保持原状添加到dst中;如果为false,则被截取的Path片段的起始点移动到dst的最后一个点,保证dst路径的连续性。
* 需要禁用硬件加速功能,setLayerType(LAYER_TYPE_SOFTWARE,null)。
* 路径截取是以左上角顺时针Path.Direction.CW或逆时针Path.Direction.CCW截取。
*/
boolean isSuccess = pathMeasure1.getSegment(0, 10, new Path(), true);
1.6、获取路径上某一长度的位置以及该位置的正切值
/**
*
* 获取路径上某一长度的位置以及该位置的正切值
* distance:距离path起始点的长度,0<=distance<=pathMeasure1.getLength()
* pos 位置的坐标值,pos[0]是x坐标,pos[1]是y坐标
* tan 位置坐标的正切值,也就是坐标到原点与X轴所成夹角对应的正切值,tan[0]是x坐标,tan[1]是y坐标,是半径为1的圆的对应点,y/x就是正切值
* 求反正切值,根据正切值获得对应夹角的度数,也就是反正切,atan(double d)传入弧度值也就是正切的结果值,atan2(double x, double y)传入正切的点的坐标值。
* 如果想要让移动点旋转至与切线重合,则旋转角度要与正切角度相同。
*/
boolean isTanSuccess = pathMeasure1.getPosTan(1, new float[]{1F, 1F}, new float[]{1F, 1F});
1.7、得到路径上某一长度的位置,以及该位置的正切值的矩阵。
/**
* 得到路径上某一长度的位置,以及该位置的正切值的矩阵。
* distance:距离Path起始点的长度
* matrix:matrix会根据flags的设置而存入不同的内容。
* flags:指定存入matrix中的内容。POSITION_MATRIX_FLAG:获取位置信息。TANGENT_MATRIX_FLAG:获取切边信息,使得图片按Path旋转。
*/
boolean isMatrixSuccess = pathMeasure1.getMatrix(1, new Matrix(), PathMeasure.POSITION_MATRIX_FLAG);
1.8、加载实例
初始化数据的时候,监听动画的数值变化,并对UI进行刷新,也就是调用onDraw重新绘制:
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE,null);
mArrow = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_arrow);
mMatrix = new Matrix();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
mPaint.setColor(Color.RED);
mDstPath = new Path();
mCirclePath = new Path();
mCirclePath.addCircle(dip2px(getContext(),100),dip2px(getContext(),100),dip2px(getContext(),25),Path.Direction.CW);
mPathMeasure = new PathMeasure(mCirclePath,true);
ValueAnimator animator = ValueAnimator.ofFloat(0,1);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取到旋转的角度值后刷新界面
mCurrentAnimValue = (Float) animation.getAnimatedValue();
invalidate();
}
});
animator.setDuration(2000);
animator.start();
}
重新绘制界面,包括绘制路径和绘制箭头位图:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mStop = mPathMeasure.getLength()*mCurrentAnimValue;
mStart = (float) (mStop-((0.5-Math.abs(mCurrentAnimValue-0.5))*mPathMeasure.getLength()));
mDstPath.reset();
mPathMeasure.getSegment(mStart,mStop, mDstPath,true);
//绘制路径
canvas.drawPath(mDstPath, mPaint);
mMatrix = new Matrix();
/**
* 第一种方式
*/
mPathMeasure.getPosTan(mStop,mPos,mTan);
float degrees = (float)(Math.atan2(mTan[1],mTan[0])*180.0/Math.PI);
mMatrix.postRotate(degrees,mArrow.getWidth()/2,mArrow.getHeight()/2);
mMatrix.postTranslate(mPos[0]-mArrow.getWidth()/2,mPos[1]-mArrow.getHeight()/2);
/**
* 第二种方式
*/
mPathMeasure.getMatrix(mStop,mMatrix,PathMeasure.POSITION_MATRIX_FLAG|PathMeasure.TANGENT_MATRIX_FLAG);
mMatrix.preTranslate(mArrow.getWidth()/2,-mArrow.getHeight()/2);
//绘制箭头
canvas.drawBitmap(mArrow,mMatrix,mPaint);
}
欢迎关注Android技术堆栈公众号: