自定义View之柱状图

来源:互联网 发布:怎么看linux的ip地址 编辑:程序博客网 时间:2024/05/19 03:21

一.效果图

因项目需要自定义一个柱状图View及饼状图View,本文先主要介绍下自定义柱状图View,饼状图View下一篇介绍,主要做个学习积累。

实现也很简单,大家可以先看下动态效果图:



二、实现步骤

代码也比较简单,就是遵循自定义View步骤顺序完成相应绘制,不清楚可以参考鸿祥大神的博客http://blog.csdn.net/lmj623565791。

1.定义HistogramView继承View,给HistogramView添加自定义属性:

以在value目录下找到attrs.xml文件,在文件中可以定义HistogramView用到的属性,比如颜色、字体大小等属性。文件内容如下:

<declare-styleable name="HistogramView">        <attr name="histogramItemWidth" format="dimension"/><!-- 柱状图项宽度 -->        <attr name="topTextColor" format="color"/><!-- 顶部文字颜色 -->        <attr name="topTextSize" format="dimension"/><!-- 顶部文字大小 -->        <attr name="axesColor" format="color"/><!-- 坐标轴颜色 -->        <attr name="axesTextColor" format="color"/><!-- 坐标轴文字颜色 -->        <attr name="axesTextSize" format="dimension"/><!-- 坐标轴文字大小 -->    </declare-styleable>


2.在.xml布局文件中对自定义的属性进行设置:

<com.cyj.histogramview.HistogramView        android:id="@+id/histogramView"        android:layout_width="match_parent"        android:layout_height="280dp"        android:layout_centerInParent="true"        android:paddingTop="40dp"        android:paddingLeft="10dp"        android:layout_centerHorizontal="true"        app:histogramItemWidth="20dp"        app:axesColor="@color/black"        app:axesTextColor="@color/mainColor"        app:axesTextSize="12sp"        app:topTextColor="@color/accentColor"        app:topTextSize="13sp"        android:background="@color/white"/>

3.在HistogramView的构造方法中获得自定义的属性,主要代码如下:

public HistogramView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HistogramView);        histogramItemWidth = typedArray.getDimension(R.styleable.HistogramView_axesTextSize, dp2px(20));        axesColor = typedArray.getColor(R.styleable.HistogramView_axesColor, getResources().getColor(R.color.accentColor));        axesTextColor = typedArray.getColor(R.styleable.HistogramView_axesTextColor, getResources().getColor(R.color.accentColor));        axesTextSize = typedArray.getDimension(R.styleable.HistogramView_axesTextSize, sp2px(12));        topTextColor = typedArray.getColor(R.styleable.HistogramView_topTextColor, getResources().getColor(R.color.accentColor));        topTextSize = typedArray.getDimension(R.styleable.HistogramView_topTextSize, sp2px(12));        typedArray.recycle();        init();    }

4.初始化画笔及一些必要变量,代码如下:

private void init() {        ani = new HistogramAnimation();        ani.setDuration(2000);        mMargin = dp2px(20);        //初始化坐标轴画笔        mAexsPaint = new Paint();        mAexsPaint.setColor(axesColor);        mAexsPaint.setAntiAlias(true);        //坐标轴文字画笔        mAexsTextPaint = new TextPaint();        mAexsTextPaint.setStyle(Paint.Style.FILL);        mAexsTextPaint.setColor(axesTextColor);        mAexsTextPaint.setTextSize(axesTextSize);        mAexsTextPaint.setAntiAlias(true);        mAexsTextPaint.setTextAlign(Paint.Align.LEFT);        //顶部文字画笔        mTopTextPaint = new TextPaint();        mTopTextPaint.setStyle(Paint.Style.FILL);        mTopTextPaint.setColor(topTextColor);        mTopTextPaint.setTextSize(topTextSize);        mTopTextPaint.setAntiAlias(true);        mTopTextPaint.setTextAlign(Paint.Align.LEFT);        //柱状图画笔        mHistogramPaint = new Paint();        mHistogramPaint.setAntiAlias(true);// 抗锯齿效果        mHistogramPaint.setStyle(Paint.Style.FILL);        mHistogramPaint.setColor(Color.parseColor("#9e95e9f3"));    }

5.重写onDraw方法。在onDraw方法中完成柱状图的绘制。代码如下:

@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mWidth = getWidth() - getPaddingLeft() - getPaddingRight();        mHeight = getHeight();        histogramHeight = mHeight - bottomAxesTextHeight - getPaddingTop();        mMarginTop = getPaddingTop();        columWidth = (int) ((mWidth - mMargin) / columCount);//项的宽度        drawAxesLineAndAxes(canvas);//绘制坐标线及y轴刻度        drawAxesText(canvas);//绘制x轴值        drawHistogramItem(canvas);//绘制柱状图及柱状图上文字    }
主要完全以下几个部分的绘制:

a.绘制坐标线及y坐标轴上的刻度,代码如下:

private void drawAxesLineAndAxes(Canvas canvas) {        // 绘制底部的线条        canvas.drawLine(0, mHeight - bottomAxesTextHeight, mWidth, mHeight - bottomAxesTextHeight, mAexsPaint);        // 绘制底部的线条        canvas.drawLine(mMargin, mMarginTop, mMargin, mHeight - bottomAxesTextHeight + mMargin, mAexsPaint);        canvas.drawText("0", mMargin / 2, mHeight - bottomAxesTextHeight, mAexsTextPaint);        canvas.drawText(maxValue + "", mMargin / 2, mHeight - bottomAxesTextHeight - histogramHeight, mAexsTextPaint);    }

b.绘制x轴值 

private void drawAxesText(Canvas canvas) {        for (int i = 0; i < columCount; i++) {            // 设置底部的文字            float textWidth = mAexsTextPaint.measureText(nameLists.get(i));            if (textWidth > columWidth) {                textWidth = columWidth / 2;            } else {                textWidth = (columWidth - textWidth) / 2;            }            TextPaint textPaint = new TextPaint();            textPaint.setColor(axesTextColor);            textPaint.setAntiAlias(true);            textPaint.setTextSize(axesTextSize);            StaticLayout layout = new StaticLayout(nameLists.get(i), textPaint, columWidth,                    Layout.Alignment.ALIGN_NORMAL, 1.0F, 0.0F, false);            canvas.save();            canvas.translate((i) * columWidth + textWidth + mMargin, mHeight - bottomAxesTextHeight + mMargin / 2);            layout.draw(canvas);            canvas.restore();//别忘了restore        }    }

c.绘制柱状图及柱状图上的该项的值,代码如下:

private void drawHistogramItem(Canvas canvas) {        // 绘制矩形        if (aniProgress != null && aniProgress.size() > 0) {            for (int i = 0; i < aniProgress.size(); i++) {// 循环遍历将柱状图形画出来                int value = aniProgress.get(i);                float left = (columWidth - histogramItemWidth) / 2 + i * columWidth + mMargin;                float right = left + histogramItemWidth;                float t = (maxValue) * 1000;                float top = histogramHeight - histogramHeight * (value / t) + mMarginTop;                float bottom = histogramHeight + mMarginTop;                //进行paint设颜色                if (i % 4 == 0) {                    mHistogramPaint.setColor(getResources().getColor(R.color.subColor));                    mTopTextPaint.setColor(getResources().getColor(R.color.subColor));                } else if (i % 4 == 1) {                    mHistogramPaint.setColor(getResources().getColor(R.color.subColor1));                    mTopTextPaint.setColor(getResources().getColor(R.color.subColor1));                } else if (i % 4 == 2) {                    mHistogramPaint.setColor(getResources().getColor(R.color.subColor2));                    mTopTextPaint.setColor(getResources().getColor(R.color.subColor2));                } else if (i % 4 == 3) {                    mHistogramPaint.setColor(getResources().getColor(R.color.subColor3));                    mTopTextPaint.setColor(getResources().getColor(R.color.subColor3));                }                RectF rect1 = new RectF(left, top, right, bottom);// 柱状图的形状                canvas.drawRoundRect(rect1, (histogramItemWidth) / 2, (histogramItemWidth) / 2, mHistogramPaint);                //设置柱形上面的文字                float textWidth = mTopTextPaint.measureText(countLists.get(i));                if (textWidth > columWidth) {                    textWidth = 0;                } else {                    textWidth = (columWidth - textWidth) / 2;                }                canvas.drawText(countLists.get(i) + "", (i) * columWidth + textWidth + mMargin, top - dp2px(10), mTopTextPaint);            }        }    }

在这一步不断改变柱状图的高度,使柱状图有个动画效果,使高度不断改变可以通过如下动画类实现:

/**     * 集成animation的一个动画类     */    private class HistogramAnimation extends Animation {        protected void applyTransformation(float interpolatedTime,                                           Transformation t) {            super.applyTransformation(interpolatedTime, t);            for (int i = 0; i < aniProgress.size(); i++) {                aniProgress.set(i, (int) (Integer.parseInt(countLists.get(i)) * 1000 * interpolatedTime));            }            invalidate();        }    }

三、使用

在Activity中初始化柱状图数据,并开启动画效果:

ArrayList<String> nameLists = new ArrayList<>();        ArrayList<String> countLists = new ArrayList<>();        for (int i=0;i<8;i++){            nameLists.add("项"+i);            countLists.add(""+new Random().nextInt(20));        }        histogramView.start(nameLists,countLists);    }}

上面已经贴出了实现的关键代码,完整demo可以参考:https://github.com/yjchen920927/HistogramView



0 0