本文共 3882 字,大约阅读时间需要 12 分钟。
先看效果图:
这里,我没有添加打钩的图片,而是单纯的用canvas来实现动画效果
中间的钩,我用了路径Path来进行描绘并实现它的动画效果。首先,这个钩由两条线段,三个顶点组成的,其实将这三个顶点作为参数传入Path对象中的lineTo()方法,再调用一下canvas.drawPath(),我们就可以得到图中这个钩的样式了
然后说说动画效果的实现,postInvalidateDelay()这个方法就很重要了,它能让onDraw()方法每隔一段时间被调用一次
所以,外部的圆环我们可以用drawArc()绘制圆弧的方式实现,每次调用onDraw()方法时绘制一定的角度,直到绘制出完整的圆环,就产生以上图中的动画效果
绘制圆环代码如下:
private int perAngle=5,currentAngle=0; //每次绘制的角度;当前已经绘制的角度@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //...... //防止绘制的角度超过360度 if(currentAngle+perAngle>360)currentAngle=360; else currentAngle+=perAngle; canvas.drawArc(circleRectF,0,currentAngle,false,circlePaint); //...... postInvalidateDelayed(5);}
最后是钩的动画实现,我首先计算了两条线段的斜率和截距:
//提供打钩的三个坐标点(radius/2,radius),(radius,(radius*3)/2),((radius*3)/2,radius/2)pathX=new int[]{radius/2,radius,(radius*3)/2};pathY=new int[]{radius,(radius*3)/2,radius/2};slopes=new float[pathX.length-1];intercepts=new float[pathX.length-1];//根据上面三个坐标点,得到两条线段,计算斜率和截距。for(int i=0;i
pathX,pathY (int[]) 记录三个顶点的坐标
slopes (float[]) 记录两条线段的斜率
intercepts (float[]) 记录两条线段的截距
然后,我们设想一下,钩的移动方向一直是向右边的,也就是x轴的正方向,所以,我们从第一个顶点出发,每次调用onDraw()方法时,沿着上面的两个线段往右跑,即每次让x坐标增大一定的值,再通过y=ax+b,就可以计算出相应的y值。将(x,y)存入Path路径中,最后通过canvas.drawPath()将新保存的路径画出来,就可以实现动画效果
具体代码如下:
private int moveX=5,currentMoveX; //钩每次绘制的长度;目前移动到的位置@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //...... //绘制完圆环后,绘制打钩 //每次向x轴的正方向移动moveX的距离来实现动画效果 if(currentAngle>=360){ //防止绘制时出边界 if(currentMoveX+moveX>pathX[pathX.length-1])currentMoveX=pathX[pathX.length-1]; else currentMoveX+=moveX; //判断目前已经绘制到哪一条线段上 for(int i=1;i
下面是自定义View的完整代码:
import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;import androidx.annotation.Nullable;public class MyProgressFinishView extends View { private Paint circlePaint; //环的画笔 private RectF circleRectF; //环的外切矩形 private Path path; //钩的路径 private Paint pathPaint; //钩的画笔 private int radius=200; //环的半径 private int perAngle=5,currentAngle=0; //每次绘制的角度;当前已经绘制的角度 private int[] pathX,pathY; private float[] slopes; //每条直线的斜率 private float[] intercepts; //每条直线的截距 private int moveX=5,currentMoveX; //钩每次绘制的长度;目前移动到的位置 private boolean isFirstMeasure=true; public MyProgressFinishView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(); } //初始化画笔 private void initPaint(){ circlePaint=new Paint(); circlePaint.setColor(Color.BLUE); circlePaint.setStrokeWidth(8); circlePaint.setStyle(Paint.Style.STROKE); pathPaint=new Paint(); pathPaint.setColor(Color.BLUE); pathPaint.setStrokeWidth(10); pathPaint.setStyle(Paint.Style.STROKE); } //初始化钩的路径 private void initPath(){ circleRectF=new RectF(circlePaint.getStrokeWidth(),circlePaint.getStrokeWidth(),radius*2,radius*2); path=new Path(); //提供打钩的三个坐标点(radius/2,radius),(radius,(radius*3)/2),((radius*3)/2,radius/2) pathX=new int[]{radius/2,radius,(radius*3)/2}; pathY=new int[]{radius,(radius*3)/2,radius/2}; slopes=new float[pathX.length-1]; intercepts=new float[pathX.length-1]; //根据上面三个坐标点,得到两条线段,计算斜率和截距。 for(int i=0;i360)currentAngle=360; else currentAngle+=perAngle; canvas.drawArc(circleRectF,0,currentAngle,false,circlePaint); //绘制完圆环后,绘制打钩 //每次向x轴的正方向移动moveX的距离来实现动画效果 if(currentAngle>=360){ //防止绘制时出边界 if(currentMoveX+moveX>pathX[pathX.length-1])currentMoveX=pathX[pathX.length-1]; else currentMoveX+=moveX; //判断目前已经绘制到哪一条线段上 for(int i=1;i
xml布局文件
转载地址:https://blog.csdn.net/zz51233273/article/details/107670430 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!