自定义View之柱状图

一.效果图

因项目需要自定义一个柱状图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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值