在上一节我们用PathMeasure实现了飞机转圈的动画,https://www.jianshu.com/p/afe60db4dd14。这是地址,这里我们实现上期打印好的做一个类似支付宝支付成功打勾的动画。效果如下:

讲之前,还是老规矩,要来看看我们要着重使用的函数,讲解一下。
nextContour
是PathMeasure的一个函数,我们都知道,Path是可以由多个不连接的线段组成,而我们的getLength与getSegment等都是对path中的第一段不连续线段的计算,如果想要计算其他的线段,那就要调用nextContour跳进去,当然,他也有返回值,跳入成功返回true,失败返回false。
现在好了,我们直接上代码,先定义自定义View,LoadedSuccessView:
public class LoadedSuccessView extends View {
private Paint paint;
private Path mDesPath;
private Path mCirclePath;
private int mCenterX;
private int mCenterY;
private int width;
private int height;
private int mRadius;
private PathMeasure mPathMeasure;
private float mAnimateValue;
private boolean mNext = false;
public LoadedSuccessView(Context context) {
this(context,null);
}
public LoadedSuccessView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public LoadedSuccessView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(getResources().getDimension(R.dimen.dp_3));
paint.setStyle(Paint.Style.STROKE);
mDesPath = new Path();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
mCenterX = width /2;
mCenterY = height /2;
mRadius = 0;
//去最小长度的一半为半径。
if(mCenterX>=mCenterY){
mRadius = mCenterY/2;
}else{
mRadius = mCenterX/2;
}
mCirclePath = new Path();
mCirclePath.addCircle(mCenterX,mCenterY,mRadius,Path.Direction.CW);//顺时针
mCirclePath.moveTo(mCenterX-mRadius/2,mCenterY);//勾的起点
mCirclePath.lineTo(mCenterX,mCenterY+mRadius/2);//勾的拐点
mCirclePath.lineTo(mCenterX+mRadius/2,mCenterY-mRadius/3);//勾的终点
mPathMeasure = new PathMeasure(mCirclePath,false);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mAnimateValue<1){
float stop = mPathMeasure.getLength() * mAnimateValue;
mPathMeasure.getSegment(0,stop,mDesPath,true);
}else{
if(!mNext){
mNext = true;
mPathMeasure.getSegment(0,mPathMeasure.getLength()*1.0f,mDesPath,true);//必须放在nextContour前
mPathMeasure.nextContour();
}
float stop = mPathMeasure.getLength() * (mAnimateValue - 1);
mPathMeasure.getSegment(0,stop,mDesPath,true);
}
canvas.drawPath(mDesPath,paint);
}
public void startAnim(){
ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,2);
valueAnimator.setDuration(4000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimateValue = (float) valueAnimator.getAnimatedValue();
invalidate();
Log.d("yanjin","mAnimateValue="+mAnimateValue+"---width="+width);
}
});
valueAnimator.start();
}
}
在LoadedSuccessView构造方法中,我们老样子,初始化paint,和真正画出来的path,在onMeasure里面我们先计算整个控件的宽高,计算出圆的中心点和半径,然后画出一个圆和一个勾的path--》mCirclePath ,这里圆的path还好说,勾的计算有点难度,这里我画了一个图来分析。:

图里面把勾的三个点的坐标计算都讲了下,至于第三点我代码里面用的是半径的三分之一,因为这样打出来的勾好看,哈哈哈。
然后在布局里面使用它,在Activity中条用即可。
final LoadedSuccessView loadedSuccessView = findViewById(R.id.view);
loadedSuccessView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loadedSuccessView.startAnim();
}
});
后面我会更新更多的自定义控件,
不喜勿喷哦。
网友评论