双柱状图

今天把上次的柱状图补上,自己也消化消化。先简单的说下绘制的过程,首先获取了屏幕的宽度,分成4份,画四个图片,然后在每个图片的两边画柱状图。然后我加了一个在不同数值范围内为不同颜色。

效果图:

双柱状图

一、柱状图代码:

public class DoubleColumnview extends View {
    Paint paint, mPaint, linePaint;//画柱状图的画笔和下面文字的画笔以及线的画笔
    Activity activity;
    private Rect mBound;//画上面文字正方形区域
    private int mStartWidth, mHeight, mWidth;//文字开始位置,屏幕高度,屏幕宽度
    private int mSize = 10;//柱状图宽度
    private int btmWith, btmHight;//图片的长度和宽度
    private List<Float> list = new ArrayList<>();
    private int len;//坐标高度
    private int spacing = 20;//图片和线的间距
    private int bitmapArray[] = {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher};
    private List<String> paintColorList = new ArrayList<>();//画笔颜色集合
    private Float maxValue = Float.valueOf(1);//最大的值
    private int padding = 20;//数字和柱状图的间距


    public DoubleColumnview(Context context) {
        super(context);

    }

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

        this.activity = (Activity) context;
        //柱状图画笔
        paint = new Paint();
        //文字画笔
        mPaint = new Paint();
        //上面文字的画笔
        linePaint = new Paint();
        //设置画笔颜色
        paint.setColor(Color.RED);
        linePaint.setColor(Color.parseColor("#ECEBEB"));
        //设置画笔抗锯齿
        paint.setAntiAlias(true);
        //线宽
        paint.setStrokeWidth(1);
        linePaint.setStrokeWidth(1);
        //画字的正方形区域
        mBound = new Rect();

    }

    public void setData(List<Databean> listBean) {

        paintColorList.clear();
        list.clear();
        maxValue = Float.valueOf(1);
        setList(listBean);
        mStartWidth = getWidth() / 5;
        invalidate();
    }

    private void setList(List<Databean> list) {
            for (int i = 0; i < list.size(); i++) {
                if (compare(list.get(i).getLow_value(), list.get(i).getTimecode_avg_result())) {
                    paintColorList.add("#FF9F52");
                } else if (compare(list.get(i).getTimecode_avg_result(), list.get(i).getHigh_value())) {
                    paintColorList.add("#C11920");
                } else {
                    paintColorList.add("#0073CF");
                }

                this.list.add(Float.parseFloat(list.get(i).getTimecode_avg_result()));
                maxValue = maxValue > Float.parseFloat(list.get(i).getTimecode_avg_result()) ? maxValue : Float.parseFloat(list.get(i).getTimecode_avg_result());
            }

    }

    private boolean compare(String value, String avg) {
        return Float.parseFloat(value) > Float.parseFloat(avg);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        len = height;
        //设置测量高度和宽度(必须要调用,不然无效果)
        setMeasuredDimension(width, height);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

//        DisplayMetrics dm = new DisplayMetrics();
//        activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
//        mWidth = dm.widthPixels;
//        mHeight = dm.heightPixels;
        mWidth = getWidth();
        mStartWidth = mWidth / 5;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画图标
        drawImageView(canvas);
    }

    private void drawImageView(Canvas canvas) {
        //为了先测量字所占的正方形空间
        mPaint.setTextSize(30);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(Color.parseColor("#626262"));
        mPaint.getTextBounds("00.00", 0, "00.00".length(), mBound);
        maxValue = maxValue * (len - btmHight - spacing) / (len - btmHight - spacing - mBound.height() - padding * 3);//y轴得最大值


        for (int i = 1; i < 5; i++) {
            //画柱状图下的图标
            Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), bitmapArray[i - 1]);
            btmWith = bitmap.getWidth();
            btmHight = bitmap.getHeight();
            canvas.drawBitmap(bitmap, mStartWidth - btmWith / 2, len - btmHight, paint);

            //画左边柱状图和左边字
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(Color.parseColor(paintColorList.get(2 * i - 2)));
            RectF rectF = new RectF();
            rectF.left = mStartWidth - mBound.width() / 2;
            rectF.right = mStartWidth - mBound.width() / 2 + mSize;
            rectF.bottom = len - btmHight - spacing;
            rectF.top = len - btmHight - spacing - (len - btmHight - spacing) * list.get(2 * i - 2) / maxValue;
            if (!(list.get(2 * i - 2) == 0.0)) {
                canvas.drawRoundRect(rectF, 6, 6, paint);
                canvas.drawText(list.get(2 * i - 2) + "", rectF.left,
                        rectF.top - padding, mPaint);
            }

            //画右边柱状图和字
            paint.setColor(Color.parseColor(paintColorList.get(2 * i - 1)));
            rectF.left = mStartWidth + mBound.width() / 2 - mSize;
            rectF.right = mStartWidth + mBound.width() / 2;
            rectF.top = len - btmHight - spacing - (len - btmHight - spacing) * list.get(2 * i - 1) / maxValue;
            if (!(list.get(2 * i - 1) == 0.0)) {
                canvas.drawRoundRect(rectF, 6, 6, paint);
                canvas.drawText(list.get(2 * i - 1) + "", rectF.left,
                        rectF.top - padding, mPaint);
            }
            mStartWidth += mWidth / 5;
        }

        canvas.drawLine(20, len - btmHight - spacing, mWidth - 20, len - btmHight - spacing, linePaint);
    }

}

因为这个柱状图很简单就不多解释了,只要注意几个地方,首先我们都知道坐标原点在屏幕左上角,右边为x正轴,下面为y正轴。

还有就是canvas.drawBitmap(bitmap, mStartWidth - btmWith / 2, len - btmHight, paint);画图片的方法,我这里是用控件高度减去图片的高,因为画的时候它是在y坐标下面开始画(画字的时候好像是从y坐标上面开始画,可以验证下),所以要移上来。

再就是画字的时候,我这里定义了一个正方形  //画字的正方形区域

   Rect mBound = new Rect();

通过mPaint.getTextBounds("00.00", 0, "00.00".length(), mBound);方法将话的字塞入正方形mBound,这样我们就能通过mBound的宽高来知道字体的所占的大小。

最后记住我们画柱状图时底部是要减去图片的高度和间距的rectF.bottom = len - btmHight - spacing;

ok了,就这么简单的画出一个柱状图来。


二、贴一下Activity和Bean类:

bean类:

public class Databean {
    private String low_value;
    private String timecode_avg_result;
    private String high_value;

    public String getLow_value() {
        return low_value;
    }

    public void setLow_value(String low_value) {
        this.low_value = low_value;
    }

    public String getTimecode_avg_result() {
        return timecode_avg_result;
    }

    public void setTimecode_avg_result(String timecode_avg_result) {
        this.timecode_avg_result = timecode_avg_result;
    }

    public String getHigh_value() {
        return high_value;
    }

    public void setHigh_value(String high_value) {
        this.high_value = high_value;
    }
}
Activity代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    DoubleColumnview doubleColumnview;
    Button btn;
    List<Databean> list = new ArrayList<>();
    Random rand;//随机数
    Databean bean;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        doubleColumnview = findViewById(R.id.double_columnview);
        btn=  findViewById(R.id.btn);
        btn.setOnClickListener(this);

        rand = new Random();
        doubleColumnview.setData(getList());
    }

    public List<Databean> getList(){
        list.clear();
        for (int i = 0;i < 8;i++) {
            bean = new Databean();
            bean.setTimecode_avg_result(String.valueOf(rand.nextInt(16) + 3));
            bean.setLow_value(String.valueOf(4));
            bean.setHigh_value(String.valueOf(10));
            list.add(bean);
        }
        return list;
    }



    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn:
                //点击事件中,调用动的方法
                doubleColumnview.setData(getList());
                break;
        }
    }
}