Android---手把手教你撸一个自定义条形图

之前从某网上看了一个描述自定义条形图的视频教程,因为没有源码,所以自己记录了一下,方便以后用到,初学者也可以互相学习.

废话不多说,首先看下效果图:(可能界面比较low哈....)


我们先看一下 画图三要素的介绍

Canvas : 画布, 绘制Bitmap操作;

Paint : 绘制所需的画笔(一般用来规定颜色,样式等);

Path : 路径 轨迹;

那么接下来直接上代码,代码中都有注释,我就不过度赘述了;

设置条形图的样式在styles.xml中:

<!--自定义条形图样式-->
<declare-styleable name="ChartStyle">
    <attr name="graphTitle" format="string"></attr>
    <attr name="xAxisName" format="string"></attr>
    <attr name="yAxisName" format="string"></attr>
    <attr name="axisTextSize" format="dimension|integer"></attr>
    <attr name="axisTextColor" format="color|integer"></attr>
</declare-styleable>

创建抽象类BaseView继承自View

public abstract class BaseView extends View {

    private Context mContext;
    //画笔
    private Paint mPaint;

    //视图的宽
    public int width;
    //视图的高
    public int height;

    //原始起点的X,Y坐标值
    public int originalX = 80;
    public int originalY = 500;


    //X,Y轴等份划分
    public int axisDividedSizeX;
    public int axisDividedSizeY;

    //第一个维度为值,第二个维度为颜色
    public int[][] columnInfo;

    //图表标题
    private String mGraphTitle;
    //XName
    private String mXAxisName;
    //YName
    private String mYAxisName;

    //坐标轴上字体的大小
    private float mAxisTextSize;
    //坐标轴字体的颜色
    public int mAxisTextColor;

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

    public BaseView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    /**
     * 设置X轴的刻度份数
     * @param axisDividedSizeX
     */
    public void setAxisDividedSizeX(int axisDividedSizeX) {
        this.axisDividedSizeX = axisDividedSizeX;
    }

    /**
     * 设置Y轴的刻度份数
     * @param axisDividedSizeY
     */
    public void setAxisDividedSizeY(int axisDividedSizeY) {
        this.axisDividedSizeY = axisDividedSizeY;
    }

    /**
     * 设置条形图的数值和颜色
     * @param columnInfo
     */
    public void setColumnInfo(int[][] columnInfo) {
        this.columnInfo = columnInfo;
    }

    public BaseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;

        //获取自定义样式
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChartStyle);

        //取出自定义的设置
        mGraphTitle = typedArray.getString(R.styleable.ChartStyle_graphTitle);
        mXAxisName = typedArray.getString(R.styleable.ChartStyle_xAxisName);
        mYAxisName = typedArray.getString(R.styleable.ChartStyle_yAxisName);

        mAxisTextColor = typedArray.getColor(R.styleable.ChartStyle_axisTextColor, context.getResources().getColor(android.R.color.black));
        mAxisTextSize = typedArray.getDimension(R.styleable.ChartStyle_axisTextSize, 12);

        //若不为null
        if (typedArray != null){
            //回收
            typedArray.recycle();
        }

        //初始化画笔
        initPaint();

    }

    //初始化画笔
    private void initPaint() {

        if (mPaint == null){
            mPaint = new Paint();
            //防抖动
            mPaint.setDither(true);
            //去锯齿
            mPaint.setAntiAlias(true);
        }
    }

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

        //视图的宽 为 屏幕的宽 - 起始位置
        width = getWidth() - originalX - 80;
        //视图的高度 为 若原始位置超过屏幕高度 则设置 屏幕高度为视图高度  否则 设置原始位置为视图高度
        height = (originalY > getHeight() ? getHeight():originalY) - 100;


        //X        drawXAxis(canvas, mPaint);
        //Y        drawYAxis(canvas, mPaint);
        //画标题
        drawTitle(canvas, mPaint);
        //X刻度
        drawXAxisScale(canvas, mPaint);
        //X刻度值
        drawXAxisScaleValue(canvas, mPaint);
        //Y刻度
        drawYAxisScale(canvas, mPaint);
        //Y刻度值
        drawYAxisScaleValue(canvas, mPaint);
        //X箭头
        drawXAxisArrow(canvas, mPaint);
        //Y箭头
        drawYAxisArrow(canvas, mPaint);
        //画柱形图
        drawColumn(canvas, mPaint);
        //画柱形图上的值
        drawColumnValue(canvas, mPaint);

    }

    /**
     * 画柱形图上的值
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawColumnValue(Canvas canvas, Paint mPaint);

    /**
     * 画柱形条
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawColumn(Canvas canvas, Paint mPaint);

    /**
     * Y轴的箭头
     * @param canvas
     * @param mPaint
     */
    private void drawYAxisArrow(Canvas canvas, Paint mPaint) {

        Path mPathY = new Path();
        //画法介绍:画一个三角形,将箭头顶点路径移动到 Y轴顶点-30的位置(), 然后X轴左右各+-10 封闭起来
        mPathY.moveTo(originalX, originalY - height - 30);
        mPathY.lineTo(originalX - 10, originalY - height);
        mPathY.lineTo(originalX + 10, originalY - height);

        mPathY.close();
        mPaint.setColor(mAxisTextColor);
        canvas.drawPath(mPathY, mPaint);
        canvas.drawText(mYAxisName, originalX - 50, originalY - height - 30, mPaint);
    }

    /**
     * X轴的箭头
     * @param canvas
     * @param mPaint
     */
    private void drawXAxisArrow(Canvas canvas, Paint mPaint) {
        Path mPathX = new Path();
        //画法介绍:其实就是画一个三角形,将箭头顶点路径移动到 X轴顶点+30的位置, 然后Y轴上下各+-10 封闭起来
        mPathX.moveTo(originalX + width + 30, originalY);
        mPathX.lineTo(originalX + width, originalY + 10);
        mPathX.lineTo(originalX + width, originalY - 10);

        mPathX.close();
        mPaint.setColor(mAxisTextColor);
        canvas.drawPath(mPathX, mPaint);
        canvas.drawText(mXAxisName, originalX + width, originalY + 50, mPaint);
    }

    /**
     * Y轴的刻度值
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawYAxisScaleValue(Canvas canvas, Paint mPaint);

    /**
     * Y轴的刻度
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawYAxisScale(Canvas canvas, Paint mPaint);

    /**
     * X轴的刻度值
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawXAxisScaleValue(Canvas canvas, Paint mPaint);

    /**
     * X轴刻度
     * @param canvas
     * @param mPaint
     */
    protected abstract void drawXAxisScale(Canvas canvas, Paint mPaint);

    /**
     * 画图表标题
     * @param canvas
     * @param mPaint
     */
    private void drawTitle(Canvas canvas, Paint mPaint) {

        if (!TextUtils.isEmpty(mGraphTitle)){
            mPaint.setTextSize(mAxisTextSize);
            mPaint.setColor(mAxisTextColor);
//            mPaint.setFakeBoldText(true);//粗体

            //要求文字宽度的中点 在其屏幕横向的中点
            canvas.drawText(mGraphTitle,
                    (getWidth()/2) - (mPaint.measureText(mGraphTitle))/2,
                    originalY + 70, mPaint );
        }
    }

    /**
     * Y     * @param canvas
     * @param mPaint
     */
    protected abstract void drawYAxis(Canvas canvas, Paint mPaint);

    /**
     * X     * @param canvas
     * @param mPaint
     */
    protected abstract void drawXAxis(Canvas canvas, Paint mPaint);
}

创建ChartView继承自BaseView并实现其中的抽象方法

public class ChartView extends BaseView {



    public ChartView(Context context) {
        super(context);
    }

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

    public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    /**
     * 画柱形图上的值
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawColumnValue(Canvas canvas, Paint mPaint) {
        float cellWidth = width/axisDividedSizeX;
        if (columnInfo != null){
            mPaint.setColor(Color.parseColor("#4682B4"));
            for (int i = 0; i < columnInfo.length; i++) {
                float leftTopY = originalY - height*(columnInfo[i][0])/axisDividedSizeY;
                canvas.drawText(columnInfo[i][0]+"",
                        (originalX + cellWidth*(i+1)) + cellWidth/2,
                        leftTopY - 10, mPaint);
            }

        }
    }

    /**
     * 画柱形条
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawColumn(Canvas canvas, Paint mPaint) {

        if (columnInfo != null){
            float cellWidth = width/axisDividedSizeX;
            for (int i = 0; i < columnInfo.length; i++) {
                mPaint.setColor(columnInfo[i][1]);
                float leftTopY = originalY - height*(columnInfo[i][0])/axisDividedSizeY;
                canvas.drawRect(originalX + cellWidth * (i + 1),
                        leftTopY, originalX+cellWidth*(i+2), originalY, mPaint);
            }
        }
    }

    /**
     * Y轴的刻度值
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawYAxisScaleValue(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setStrokeWidth(2);
        float cellHeight = height / axisDividedSizeY;
        for (int i = 0; i < axisDividedSizeY; i++) {
            canvas.drawText(String.valueOf(i),
                    originalX - 30,
                    originalY - cellHeight * i + 10, mPaint);
        }
    }

    /**
     * Y轴的刻度
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawYAxisScale(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setStrokeWidth(2);
        float cellHeight = height / axisDividedSizeY;
        for (int i = 0; i < axisDividedSizeY - 1; i++) {
            canvas.drawLine(originalX, (originalY - cellHeight * (i+1)),
                    originalX + 10, (originalY - cellHeight * (i+1)), mPaint);
        }
    }

    /**
     * X轴的刻度值
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawXAxisScaleValue(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setTextSize(16);
//        mPaint.setFakeBoldText(true);
        float cellWidth = width/axisDividedSizeX;
        for (int i = 0; i < axisDividedSizeX; i++) {
            canvas.drawText(String.valueOf(i), cellWidth * (i+1) + originalX - 35,
                    originalY + 30, mPaint);
        }

    }

    /**
     * X轴刻度
     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawXAxisScale(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setStrokeWidth(2);
        float cellWidh = width / axisDividedSizeX;
        for (int i = 0; i < axisDividedSizeX - 1; i++) {
            canvas.drawLine(cellWidh * (i+1) + originalX,
                    originalY,
                    cellWidh * (i+1) + originalX,
                    originalY- 10, mPaint );
        }
    }

    /**
     * Y     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawYAxis(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setStrokeWidth(3);
        canvas.drawLine(originalX, originalY, originalX, originalY- height, mPaint);

    }

    /**
     * X     * @param canvas
     * @param mPaint
     */
    @Override
    protected void drawXAxis(Canvas canvas, Paint mPaint) {

        mPaint.setColor(mAxisTextColor);
        mPaint.setStrokeWidth(3);
        canvas.drawLine(originalX, originalY, originalX + width, originalY, mPaint);
    }
}
设置xml布局文件,很简单就只有一个自定义的ChartView

<com.example.joy.chartsdemo.view.ChartView
    android:id="@+id/chartview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:graphTitle="ChartView条形图"
    app:axisTextColor="#20B2AA"
    app:xAxisName=""
    app:yAxisName="个数"
    app:axisTextSize="20sp" />

最后在MainActivity中onCreate()设置自定义的ChartView的一些属性.

ChartView mChartView = findViewById(R.id.chartview);

int[][] columnInfo = new int[][]{
        {6, Color.parseColor("#FFA500")},
        {2, Color.parseColor("#FFD700")},
        {8, Color.parseColor("#BC8F8F")},
        {6, Color.parseColor("#DB7093")},
        {7, Color.parseColor("#FFA500")},
        {9, Color.parseColor("#DAA520")},
        {10, Color.parseColor("#9932CC")},
};

mChartView.setColumnInfo(columnInfo);
mChartView.setAxisDividedSizeX(10);
mChartView.setAxisDividedSizeY(10);

the end...

烦请大家尊重原创者版权,转载请标明出处:https://blog.csdn.net/JOYU_/article/details/80911719


猜你喜欢

转载自blog.csdn.net/joyu_/article/details/80911719