自定义view首当其冲第一步就是去怎么设计 :
在这里附上编写自定义view时的设计 并附上源码
如果有大牛觉得有不足的地方欢迎来喷 ,嘻嘻嘻
public class StepArecView extends View { /** * 设计思路: * * 1,先获取到控件定义的位置大小信息(应为是圆环所以应该为正方形 如果长宽不一致 可以自由选择最大值或者最小值都可 ) * 2,得到长宽信息后 定义一个准备绘制矩形的对象RectF (我们绘制的圆环是该矩形的内切圆 所以参数传值的时候需要计算好) * 3,开始绘制未加载部分圆环 drawArc 当然圆环不需要内填充 所以我们需要定义画笔Paint的宽度来确定圆环的宽度 * 4,drawArc 中第二个参数是指起始角度(以180度角为基准 顺时针计算) 第三个参数就是我们需要圆环的总角度最大360 * 5,开始绘制已加载部分圆环 和绘制未加载圆环一样 不同的是 已加载部分圆环会不断的修改已加载的角度(动效) 当然不带动效的自行路过 可以忽略 * 6,计算已加载部分圆环的角度 (当前值/总进度值 *最大角度值 )这便是已加载圆环的该显示的角度了 * 7,绘制矩形文字在圆环中心(自行略过 也就两句代码) * 8,然后 就是我们的动画了 这里我们暴露了个方法setCurrentCount给activity调用方便传递总进度值和当前进度值 然后有动画效果的绘制进度值 * 这里我们用到了ValueAnimator 在addUpdateListener回掉方法中不停的去重新绘制已加载进度值 (不懂可以去看setAnimation方法) * * */ private float borderWidth=50f;//圆弧的宽度 private float numberTextSize=13;//字体大小 private String stepNumber="0";//多少步 private float startAngle=135;//圆弧的角度 private float angleLength=270;//整个圆弧划过的角度 private float currentAngleLength=260;//默认是已加载进度表示的角度 private int animationLength=3000;//动画时长 public StepArecView(Context context) { this(context,null); } public StepArecView(Context context, AttributeSet attrs) { this(context, attrs,0); } public StepArecView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float centerX=getWidth()/2; /** * 原型内接矩形 圆弧是该巨型的外接圆构成 */ RectF rectF=new RectF(0+borderWidth,borderWidth,2*centerX-borderWidth,2*centerX-borderWidth); drawArcYello(canvas,rectF); drawArcRed(canvas,rectF); drawTextValue(canvas,centerX); } /** * 绘制全部进度 * @param canvas * @param rectF */ private void drawArcYello(Canvas canvas, RectF rectF) { Paint paint1=new Paint(); paint1.setColor(Color.YELLOW); //设置接口处为圆弧 paint1.setStrokeJoin(Paint.Join.ROUND); paint1.setStrokeCap(Paint.Cap.ROUND);//设置画笔的样式是圆形还是矩形 paint1.setStyle(Paint.Style.STROKE); paint1.setAntiAlias(true); paint1.setStrokeWidth(borderWidth); canvas.drawArc(rectF,startAngle,angleLength,false,paint1); } private void drawArcRed(Canvas canvas,RectF rectF){ Paint paint2=new Paint(); paint2.setColor(Color.RED); //设置接口处为圆弧 paint2.setStrokeJoin(Paint.Join.ROUND); paint2.setStrokeCap(Paint.Cap.ROUND);//设置画笔的样式是圆形还是矩形 paint2.setStyle(Paint.Style.STROKE); paint2.setAntiAlias(true); paint2.setStrokeWidth(borderWidth); canvas.drawArc(rectF,startAngle,currentAngleLength,false,paint2); } private void drawTextValue(Canvas canvas,float centerX){ Paint paint3=new Paint(); paint3.setTextSize(dipToPx(18)); paint3.setAntiAlias(true); paint3.setTextAlign(Paint.Align.CENTER); paint3.setColor(Color.RED); String text=String.valueOf(currentAngleLength); Rect rect=new Rect(); paint3.getTextBounds(text,0,text.length(),rect); canvas.drawText(text,centerX,getHeight()/2+rect.height(),paint3); } public void setCurrentCount(int maxCount,int nowCount){ float scale=(float) nowCount/maxCount; setAnimation(0,scale*angleLength,animationLength); } /** * 为进度设置动画 * ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的, * 而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。 * 它的内部使用一种时间循环的机制来计算值与值之间的动画过渡, * 我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长, * 那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。 * * @param last * @param current */ private void setAnimation(float last, float current, int length) { ValueAnimator progressAnimator = ValueAnimator.ofFloat(last, current); progressAnimator.setDuration(length); progressAnimator.setTarget(currentAngleLength); progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentAngleLength = (float) animation.getAnimatedValue(); invalidate(); } }); progressAnimator.start(); } /** * dip 转换成px * * @param dip * @return */ private int dipToPx(float dip) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1)); } }