Android 绘制刻度表盘
2021-03-11 本文已影响0人
带带我
效果图和代码
WeChat_20210311180033.gif
public class NetSpeedDialPlateView extends View {
private int preWidth;
private int preHeight;
private Paint paintTranArc;
private Paint paint1;
//最外层单线画笔
private Paint paintOutSideLine;
//加载动起来的圆弧
private Paint paintLoadArc;
private float row;
private Bitmap bmp;
//刻度文字 0-100
private Paint paintDu;
//指针画笔
private Paint paintPointer;
private Path pathDu;
//表盘尺寸
private int sideLength;
//适配不同分辨率
private float sizeScale = 1f;
public NetSpeedDialPlateView(Context context) {
this(context, null);
}
public NetSpeedDialPlateView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public NetSpeedDialPlateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
sizeScale = ((Activity)(context)).getWindowManager().getDefaultDisplay().getWidth()/1080f;
SoutUtils.out("sizeScale == " + sizeScale);
paintTranArc = new Paint();
paintTranArc.setStyle(Paint.Style.STROKE);
paintTranArc.setColor(Color.parseColor("#66ffffff"));
paintTranArc.setStrokeWidth(70f*sizeScale);
paintTranArc.setAntiAlias(true);
//刻度
paint1 = new Paint();
paint1.setStyle(Paint.Style.STROKE);
paint1.setColor(Color.WHITE);
paint1.setStrokeWidth(30f*sizeScale);
paint1.setAntiAlias(true);
paintOutSideLine = new Paint();
paintOutSideLine.setAntiAlias(true);
paintOutSideLine.setStrokeWidth(3f);
paintOutSideLine.setStyle(Paint.Style.STROKE);
paintOutSideLine.setColor(Color.WHITE);
paintLoadArc = new Paint();
paintLoadArc.setAntiAlias(true);
paintLoadArc.setStrokeWidth(70f*sizeScale);
paintLoadArc.setStyle(Paint.Style.STROKE);
paintLoadArc.setColor(Color.WHITE);
paintDu = new Paint();
paintDu.setTextAlign(Paint.Align.RIGHT);
paintDu.setTextSize(48*sizeScale);
paintDu.setAntiAlias(true);
paintDu.setColor(Color.WHITE);
paintPointer = new Paint();
paintPointer.setAntiAlias(true);
paintPointer.setTextSize(40*sizeScale);
pathDu = new Path();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
preWidth = MeasureSpec.getSize(widthMeasureSpec);
preHeight = MeasureSpec.getSize(heightMeasureSpec);
int max = Math.max(preWidth, preHeight);
if (max < 240) {
sideLength = 240;//保证刻度清晰可见,设置边长下限
} else {
sideLength = max;
}
// sideLength = (int) (sideLength*sizeScale);
//通过path绘制棱形表盘指针
bmp = Bitmap.createBitmap((int)(100*sizeScale), sideLength / 2 - (int)(130*sizeScale), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint6 = new Paint();
paint6.setAntiAlias(true);
paint6.setColor(getResources().getColor(R.color.white));
Path path = new Path();
path.moveTo(50*sizeScale, 0);
path.lineTo(80*sizeScale, 50*sizeScale);
path.lineTo(50*sizeScale, sideLength / 2 - 130*sizeScale);
path.lineTo(20*sizeScale, 50*sizeScale);
path.lineTo(50*sizeScale, 0);
RectF rectF = new RectF(0, 0, 100*sizeScale-1, 100*sizeScale-1);
path.addArc(rectF, 0, 360);
canvas.drawPath(path, paint6);
canvas.drawBitmap(bmp, 0, 0, paint6);
canvas.save();
canvas.restore();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF oval2 = new RectF(50*sizeScale, 50*sizeScale, sideLength - 50*sizeScale, sideLength - 50*sizeScale);//绘制区域
//绘制半透明圆弧 从135度开始绘制270度
canvas.drawArc(oval2, 135, 270, false, paintTranArc);
//绘制刻度线
RectF oval3 = new RectF(110*sizeScale, 110*sizeScale, sideLength - 110*sizeScale, sideLength - 110*sizeScale);//
float i1 = (270.0f - 110) / 99;
float startAngle = 135;
ArrayList<Float> floats = new ArrayList<>();
for (int i = 0; i < 11; i++) {
floats.add(startAngle);
if (i == 9){
startAngle += 26;
} else {
startAngle += 27;
}
}
for (int i = 0; i < floats.size(); i++) {
canvas.drawArc(oval3, floats.get(i), 1, false, paint1);
}
//刻度数绘制,通过path确定位置,然后通过drawTextOnPath绘制text
RectF oval4 = new RectF(170*sizeScale, 170*sizeScale, sideLength - 170*sizeScale, sideLength - 170*sizeScale);//
float pathstart = 114;
for (int i = 0; i < 11; i++) {
pathDu.reset();
pathDu.arcTo(oval4, pathstart, 27);
//这也可以啊
//pathDu.addArc(oval4, pathstart,27);
int scale = i*10;
String scaleStr = String.valueOf(scale);
if (scale == 0){
//当刻度是0的时候 有点对不齐
scaleStr = scaleStr + " ";
}
//如果使用 drawText()方法,需要计算文本Text所在坐标
canvas.drawTextOnPath(scaleStr, pathDu, 0, 0, paintDu);
pathstart += 27;
}
canvas.save();
//绘制外层单线条
RectF ovalLine = new RectF(2, 2, sideLength - 2, sideLength - 2);
//初始绘制有偏离,这里的row要处理
canvas.drawArc(ovalLine, 135, row - 45, false, paintOutSideLine);
//绘制加载后的圆弧
canvas.drawArc(oval2, 135, row - 45, false, paintLoadArc);
canvas.rotate(row, sideLength / 2, sideLength / 2);
canvas.drawBitmap(bmp, sideLength / 2 - 50*sizeScale, sideLength / 2 - 50*sizeScale, paintPointer);
canvas.restore();
}
public void setData(float minNumb, float maxNumb, float temp, OnSpeedChangeListener listener) {
float span = maxNumb - minNumb;//跨度
float v = 100.0f / span;
ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0, 1);
mValueAnimator.setDuration(2500);
// 中间加速的插值器,也可以使用其他
mValueAnimator.setInterpolator(new BounceInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = (Float) animation.getAnimatedValue();
//计算出的旋转角度,由于前面绘制指针控件的角度是垂直向下的,表盘的起始角度是135度,所有加45度
row = 2.7f * (temp - minNumb) * v * fraction + 45;
listener.onChange(fraction);
postInvalidate();
}
});
mValueAnimator.start();
}
/**
* 对外提供接口,获取动画差值
*/
public interface OnSpeedChangeListener{
void onChange(float fraction);
}
}