只有最基本的表盘跟指针没弄动画。
主要是onDraw方法
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(mWidth / 2, mHeight / 2);//移动坐标原点到中心 RectF rectF = new RectF(-mWidth/2 + padding,-mHeight/2+padding,mWidth/2-padding,mHeight/2-padding); canvas.drawArc(rectF,135,270,false,mCiclePaint); drawNum(canvas);//画仪表盘刻度 drawerPointer(canvas,progress);//画指针 drawCenterCircle(canvas);//画指针圆心 drawProgressText(canvas); //画仪表盘进度值 }
仪表盘的刻度其实是通过旋转画布来画的,比如50刻度我只要drawLine一下 画一个竖直的线就行了,画它右边的在把画布旋转个2.7度再画一个竖线就行了类似的循环旋转画布,循环画竖线。
private void drawNum(Canvas canvas){ canvas.save(); canvas.rotate(-135,0,0); int indexY = -mHeight/2+10; canvas.drawLine(0,indexY+20,0,indexY+40,mScalePaint); float rAngle = 270/(100*1.0f); for (int i = 0; i <=100 ; i++) { canvas.save(); //记录画布状态 canvas.rotate(rAngle * i, 0, 0); if (i==0 || i%5==0){ canvas.drawLine(0,indexY+20,0,indexY+40,mScalePaint); if (i%10==0){ canvas.drawText(i+"",-DisPlayUtils.dp2px(6),indexY+70,mTextPaint); } }else { canvas.drawLine(0,indexY+20,0,indexY+30,mScalePaint); } canvas.restore(); } canvas.restore(); }
仪表盘外圈的drawArc画弧线的话,起始点要旋转135度,弧度270度才行。
canvas.drawArc(rectF,135,270,false,mCiclePaint);
rectF是一个矩形,只有top left bottom right 4个参数用来限制圆弧的位置不能超过这几个坐标,否则就不显示了。
画表盘的画笔我们指定只描边不要填充了,规定描边的宽度
mCiclePaint.setStyle(Paint.Style.STROKE); mCiclePaint.setStrokeWidth(20);
画笔颜色的渐变是个
SweepGradient类 这个是控制弧形渐变的当然还有线性渐变等,不解释了。没怎么用过。
构造函数之一
public SweepGradient(float cx, float cy, @RecentlyNonNull int[] colors, @RecentlyNullable float[] positions) {}
圆心坐标,前2个,color是指颜色渐变的数组,颜色会从数组里的第一个渐变到最后一个,最后一个是positions也是一个数组跟colors对应,指定colors数组中的单个color渐变的比例默认是平分的,可以通过positions的大小来改变占用大小.positions如 0.1f,0.3f。2个数组长度保持一致,0.3f对应的颜色占的比例就是0.1的3倍了。
本例子中变盘colors中的第一个是蓝色,最有一个是红色,如果不用
Matrix gradientMatrix = new Matrix();
gradientMatrix.preRotate(135);来做旋转的话,蓝色的起始位置就会在园0度位置,而不是135度位置。
这样表盘的外面彩色的就画完了 里面的刻度通过循环旋转画line也可以完成,数值也是在循环为10的倍数时 drawLine的下方改变一下Y值。drawText就行。
最后是指针。
private void drawerPointer(Canvas canvas,float progress){ canvas.save(); canvas.rotate( -135+270/(100*1.0f)*progress); Path pointPath = new Path(); RectF pointF = new RectF(-10,-10,10,10); pointPath.moveTo(0,-mWidth/4); pointPath.lineTo(-10,0); pointPath.addArc(pointF,0,180); pointPath.lineTo(0,-mWidth/4); canvas.drawPath(pointPath,mPointPaint); canvas.restore(); }
指针分为2个部分 一个三角形跟一个半圆,lineTo连接一个三角形,addArc来画半圆。组合成一个指针,指针旋转就通过旋转画布完成。
package com.yunhe.secondarywater.ui.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.view.View; import com.yunhe.secondarywater.utils.DisPlayUtils; /** * Created by wuzhi.peng on 2019/7/2 **/ public class DashboardView extends View { private int padding = 20; private int mWidth; private int mHeight; private float progress; private Paint mScalePaint; private Paint mCiclePaint; private Paint mTextPaint; private Paint mPointPaint; private Paint mCenterCiclePaint; private Paint mProgressTextPaint; public DashboardView(Context context) { this(context,null); } public DashboardView(Context context, AttributeSet attrs) { this(context, attrs,0); } public DashboardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScalePaint = new Paint(); mScalePaint.setDither(true); mScalePaint.setAntiAlias(true); mScalePaint.setColor(Color.BLACK); mScalePaint.setStyle(Paint.Style.STROKE); mScalePaint.setStrokeWidth(2); mCiclePaint = new Paint(); mCiclePaint.setDither(true); mCiclePaint.setAntiAlias(true); mCiclePaint.setStyle(Paint.Style.STROKE); mCiclePaint.setStrokeWidth(20); mTextPaint = new Paint(); mTextPaint.setStyle(Paint.Style.STROKE); mTextPaint.setTextSize(DisPlayUtils.dp2px(12)); mTextPaint.setAntiAlias(true); mTextPaint.setColor(Color.BLACK); mPointPaint = new Paint(); mPointPaint.setAntiAlias(true); mPointPaint.setDither(true); mPointPaint.setColor(Color.RED); mCenterCiclePaint = new Paint(); mCenterCiclePaint.setColor(Color.WHITE); mCenterCiclePaint.setAntiAlias(true); mCenterCiclePaint.setDither(true); mProgressTextPaint = new Paint(); mProgressTextPaint.setDither(true); mProgressTextPaint.setAntiAlias(true); mProgressTextPaint.setStyle(Paint.Style.STROKE); mProgressTextPaint.setTextSize(DisPlayUtils.dp2px(20)); SweepGradient gradient = new SweepGradient(0,0,new int[]{Color.parseColor("#3bc1ff"), Color.parseColor("#3fc6fa"), Color.parseColor("#5fc6d2"),Color.parseColor("#90c691"),Color.parseColor("#ccc643"), Color.parseColor("#fdc602"),Color.parseColor("#ff9300"),Color.parseColor("#ff5100"), Color.parseColor("#fa2300"),Color.parseColor("#ee0d07"),Color.parseColor("#d3162b"),},null); Matrix gradientMatrix = new Matrix(); gradientMatrix.preRotate(135); gradient.setLocalMatrix(gradientMatrix); mCiclePaint.setShader(gradient); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getWidth(); mHeight = getHeight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(mWidth / 2, mHeight / 2);//移动坐标原点到中心 RectF rectF = new RectF(-mWidth/2 + padding,-mHeight/2+padding,mWidth/2-padding,mHeight/2-padding); canvas.drawArc(rectF,135,270,false,mCiclePaint); drawNum(canvas);//画仪表盘刻度 drawerPointer(canvas,progress);//画指针 drawCenterCircle(canvas);//画指针圆心 drawProgressText(canvas); //画仪表盘进度值 } public void setProgress(float progress){ if (progress<0)progress=0; if (progress>100)progress=100; this.progress = progress; invalidate(); } private void drawNum(Canvas canvas){ canvas.save(); canvas.rotate(-135,0,0); int indexY = -mHeight/2+10; canvas.drawLine(0,indexY+20,0,indexY+40,mScalePaint); float rAngle = 270/(100*1.0f); for (int i = 0; i <=100 ; i++) { canvas.save(); //记录画布状态 canvas.rotate(rAngle * i, 0, 0); if (i==0 || i%5==0){ canvas.drawLine(0,indexY+20,0,indexY+40,mScalePaint); if (i%10==0){ canvas.drawText(i+"",-DisPlayUtils.dp2px(6),indexY+70,mTextPaint); } }else { canvas.drawLine(0,indexY+20,0,indexY+30,mScalePaint); } canvas.restore(); } canvas.restore(); } private void drawerPointer(Canvas canvas,float progress){ canvas.save(); canvas.rotate( -135+270/(100*1.0f)*progress); Path pointPath = new Path(); RectF pointF = new RectF(-10,-10,10,10); pointPath.moveTo(0,-mWidth/4); pointPath.lineTo(-10,0); pointPath.addArc(pointF,0,180); pointPath.lineTo(0,-mWidth/4); canvas.drawPath(pointPath,mPointPaint); canvas.restore(); } private void drawCenterCircle(Canvas canvas){ canvas.drawCircle(0,0,5,mCenterCiclePaint); } private void drawProgressText(Canvas canvas){ String text = progress+"%"; if ( progress>=0 && progress<=60){ mProgressTextPaint.setColor(Color.parseColor("#3bc1ff")); }else if (progress>60&&progress<=80){ mProgressTextPaint.setColor(Color.parseColor("#ff5100")); }else if (progress>80){ mProgressTextPaint.setColor(Color.parseColor("#ee0d07")); } canvas.drawText(progress+"%",-getTextLength(mProgressTextPaint,text)/2,mHeight/2-DisPlayUtils.dp2px(10),mProgressTextPaint); } private float getTextLength(Paint paint,String text){ return paint.measureText(text); } }
源码还是比较简单,没有搞很复杂,也没有用自定义的属性,不过用的时候宽高要一样不然就变形了这个要在onMesure的时候去搞一下 强制宽高相等取小的。