Bootstrap

如何绘制一个仪表盘

  • 学习使用 Paint/Path/PathMeasure/PathDashPathEffect来绘制一个仪表盘

  • PathMeasure:支持Path路径的测量,还有路径上任意距离的点的位置和角度

  • PathDashPathEffect:用指定的形状标记绘制的路径,可以通过Paint.setPathEffect设置给画笔,用于绘制表盘


public class Dashboard extends View {
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private static final int ANGLE = 120;
    private static final float RADIUS = Util.dp2px(150);
    private static final float LENGTH = Util.dp2px(120);
    private static final int count = 20;
    private PathMeasure pathMeasure;
    Path dash = new Path();
    PathDashPathEffect effect;

    Path arc = new Path();

    public Dashboard(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(Util.dp2px(2));
        dash.addRect(0, 0, Util.dp2px(2), Util.dp2px(10), Path.Direction.CW);


    }

    float pos[] = new float[2];
    float tan[] = new float[2];

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        arc = new Path();
        arc.addArc(getWidth()/2-RADIUS, getHeight()/2-RADIUS, getWidth()/2+RADIUS, getHeight()/2+RADIUS, 90+ANGLE/2, 360-ANGLE);

        pathMeasure = new PathMeasure(arc, false);
        float length = pathMeasure.getLength();
        float advance = length/(count);//-Util.dp2px(0);
        effect = new PathDashPathEffect(dash, advance, 0, PathDashPathEffect.Style.ROTATE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画刻度
        canvas.drawPath(arc, paint);
//        canvas.drawArc(getWidth()/2-RADIUS, getHeight()/2-RADIUS, getWidth()/2+RADIUS, getHeight()/2+RADIUS, 90+ANGLE/2, 360-ANGLE, false, paint);
        paint.setPathEffect(effect);

        canvas.drawPath(arc, paint);
//        canvas.drawArc(getWidth()/2-RADIUS, getHeight()/2-RADIUS, getWidth()/2+RADIUS, getHeight()/2+RADIUS, 90+ANGLE/2, 360-ANGLE, false, paint);
        paint.setPathEffect(null);

        // 画指针
//        boolean success = pathMeasure.getPosTan(2900, pos, tan);
//        if (success)
//            canvas.drawLine(getWidth()/2, getHeight()/2, pos[0], pos[1], paint);

        int markValue = getMark();
        canvas.drawLine(getWidth()/2, getHeight()/2,
                (float) Math.cos(Math.toRadians(getAngleFromMark(markValue)))*LENGTH + getWidth()/2,
                (float) Math.sin(Math.toRadians(getAngleFromMark(markValue)))*LENGTH + getHeight()/2,
                paint);

        postDelayed(this::invalidate, 1000);
    }

    int mark = 0;
    int getMark(){
        mark++;
        if (mark > 20) mark = 0;
        return mark;
    }

    int getAngleFromMark(int mark){
        return (int) (90 + (float) ANGLE / 2 + (float)(360-ANGLE)/count*mark);
    }
}