Android自定义圆角条形图表

安卓的图表框架比较常用的有HelloChart和MPAndroidChart。HelloChart据说性能优化比较好,但是我根据我的个人经验,MPAndroidChart能实现的样式比较多。不得不说的是,在实际需求中,无论用哪个框架,把图表样式改得跟UI图一致都要费很大很大很大的力气。

当框架无法满足UI需求的效果时,就需要自定义了。以下是我绘制的图表效果:

image

下面贴代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import java.util.List;

/**
 * 条形(圆角)图表控件。编写原因:图表框架无法符合UI需求
 *
 */
public class BarChartView extends View {
    private Paint mPaint;
    private int mXAxisTextColor = convertColor("#9D9999");
    private int mXAxisLineColor = convertColor("#231d1d26");
    private int mBarColor = convertColor("#F6BF18");
    private float mXAxisLineWidth = dp2px(0.5f);
    private float mXAxisTextSize = dp2px(11.793f);
    private float mXAxisLabelMarginTop = dp2px(8.844f);
    private float mBarWidth = dp2px(4.913f);
    private float mChartPaddingTop = dp2px(5.896f);
    private float mChartPaddingLeft = dp2px(14.741f);

    private int mMaxValue;


    private List<String> mXAxisLabels;
    private List<Integer> mXAxisValues;

    public BarChartView(Context context) {
        this(context, null);
    }

    public BarChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BarChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //条形的起点
        float barStartY = getHeight() - mXAxisTextSize - mXAxisLineWidth - mXAxisLabelMarginTop - mChartPaddingTop;

        //画x轴文字
        if (mXAxisLabels != null && mXAxisValues != null && mXAxisValues.size() == mXAxisLabels.size()) {
            float delta = (getWidth() - mChartPaddingLeft * 2) / mXAxisLabels.size();
            for (int i = 0, len = mXAxisLabels.size(); i < len; i++) {
                mPaint.setColor(mXAxisTextColor);
                mPaint.setTextSize(mXAxisTextSize);
                mPaint.setStyle(Paint.Style.FILL);
                if (i == len - 1) {
                    mPaint.setColor(Color.BLACK);
                }
                float textSize = mPaint.measureText(mXAxisLabels.get(i));
                if (i == 0 && len > 12) {//月份视图,第一个X轴文本
                    canvas.drawText(mXAxisLabels.get(i), 0, getHeight() - mXAxisTextSize / 2, mPaint);
                } else {
                    canvas.drawText(mXAxisLabels.get(i), i * delta + delta / 2 - textSize / 2 + mChartPaddingLeft, getHeight() - mXAxisTextSize / 2, mPaint);
                }

                //画条形
                if (mMaxValue > 0) {//根据需求,下限(最小值)是0,固定的。
                    mPaint.setStyle(Paint.Style.STROKE);
                    mPaint.setStrokeCap(Paint.Cap.ROUND);
                    mPaint.setColor(mBarColor);
                    mPaint.setStrokeWidth(mBarWidth);

                    float positionX = i * delta + delta / 2 + mChartPaddingLeft;
                    canvas.drawLine(positionX, barStartY,
                            positionX, barStartY - (mXAxisValues.get(i) * 1.0f / mMaxValue * 1.0f * (barStartY-mChartPaddingTop)), mPaint);
                }
            }
        }

        //画x轴横线
        mPaint.setStrokeWidth(mXAxisLineWidth);
        mPaint.setColor(mXAxisLineColor);
        canvas.drawLine(0, getHeight() - mXAxisLabelMarginTop - mXAxisTextSize, getWidth(), getHeight() - mXAxisTextSize - mXAxisLabelMarginTop, mPaint);
        //画顶部的横线
        canvas.drawLine(0, 0, getWidth(), 0, mPaint);

        //画最小值
        mPaint.setColor(mXAxisTextColor);
        mPaint.setTextSize(mXAxisTextSize);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawText("0", getWidth() - mPaint.measureText("0"), barStartY, mPaint);
        //画最大值
        mPaint.setColor(mBarColor);
        canvas.drawText(mMaxValue + "", getWidth() - mPaint.measureText(mMaxValue + ""), mChartPaddingTop + mXAxisTextSize / 2, mPaint);
    }

    public void setXAxisLabels(List<String> xAxisLabels) {
        this.mXAxisLabels = xAxisLabels;
    }

    public void setXAxisValues(List<Integer> xAxisValues) {
        this.mXAxisValues = xAxisValues;
        this.mMaxValue = 0;
        if (this.mXAxisValues != null) {
            //求最大值
            for (int item : mXAxisValues) {
                if (item > this.mMaxValue) {
                    this.mMaxValue = item;
                }
            }
        }
    }

    public void notifyDataSetChanged() {
        invalidate();
    }

    public void setBarColor(int barColor) {
        this.mBarColor = barColor;
    }

    private int convertColor(String colorStr) {
        return Color.parseColor(colorStr);
    }

    private float dp2px(float dpVal) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, getResources().getDisplayMetrics());
    }

使用:

在xml里:

 <BarChartView
    android:id="@+id/chart"
    android:layout_width="match_parent"
    android:layout_height="200dp" />

给图表设置数据:

//周视图的数据
private void initWeekData() {
        List<String> data = new ArrayList<>();
        data.add("8月7日");
        data.add("8");
        data.add("9");
        data.add("10");
        data.add("11");
        data.add("12");
        data.add("13");

        List<Integer> values = new ArrayList<>();
        values.add(10);
        values.add(1);
        values.add(14);
        values.add(3);
        values.add(7);
        values.add(0);
        values.add(9);

        setChartData(data, values);
    }
    //月视图的数据
    private void initMonthData() {
        List<String> data = new ArrayList<>();
        data.add("7月16日");
        for (int i = 17; i <= 31; i++) {
            if (i == 20 || i == 26) {
                data.add(i + "");
            } else {
                data.add("");
            }
        }
        for (int i = 1; i <= 13; i++) {
            if (i == 1 || i == 7 || i == 13) {
                data.add(i + "");
            } else {
                data.add("");
            }
        }

        List<Integer> values = new ArrayList<>();
        for (int i = 0;i<data.size();i++){
            values.add(new Random().nextInt(15));
        }

        setChartData(data, values);
    }
    //年视图的数据
    private void initYearData() {
        List<String> data = new ArrayList<>();
        data.add("15年9月");
        for (int i = 0; i <3; i++) {
            data.add("");
        }
        for (int i = 1; i <= 8; i++) {
            if (i == 1 || i == 5 || i == 8) {
                data.add(i + "月");
            } else {
                data.add("");
            }
        }

        List<Integer> values = new ArrayList<>();
        for (int i = 0;i<data.size();i++){
            values.add(new Random().nextInt(15));
        }

        setChartData(data, values);
    }

    private void setChartData(List<String> data, List<Integer> values) {
        chart.setXAxisLabels(data);//X轴的文本
        chart.setXAxisValues(values);//X轴对应的值
        chart.setBarColor(0xff1BB3F9);//条形的颜色
        chart.notifyDataSetChanged();
    }
发布了32 篇原创文章 · 获赞 39 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/zengd0/article/details/52738829