美文网首页Android
Android 绘制刻度表盘

Android 绘制刻度表盘

作者: 带带我 | 来源:发表于2021-03-11 18:03 被阅读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);
    }
}

相关文章

网友评论

    本文标题:Android 绘制刻度表盘

    本文链接:https://www.haomeiwen.com/subject/gldoqltx.html