Android柱形图 绘制

来源:互联网 发布:阿里备案域名交易 编辑:程序博客网 时间:2024/06/10 21:27

一直在维护www.halloandroid.com我的个人博客网站,发现漏了一篇没发在上面,补回来。

上次写了一篇有关自定义折线图的文章,今天写一篇关于柱形图的文章,因为看了网上一位阿拉丁神灯大神的文章,所以自己也想动手写一个,熟练和学习一下自定义View。话不多说,开始撸!

整体的思路:

画柱状图 –>画竖线 –>画顶部横线 –>画文字

自定义View四步骤走起;

还是我们自定View的那几个步骤:

  • 1、自定义View的属性
  • 2、在View的构造方法中获得我们自定义的属性
  • [ 3、重写onMesure ]
  • [ 4、重写onLayout ]
  • 5、重写onDraw

一,在attrs里面进行声明

 <declare-styleable name="HistogramView">        <attr name="cylinderColor" format="color|reference"/><!--柱体颜色-->        <attr name="axesColor" format="color|reference"/><!--坐标线颜色-->        <attr name="textColor"/><!--文字颜色-->        <attr name="cylinderWith" format="integer"/><!--主题宽度-->        <attr name="maxSize" format="float"/><!--最大值-->        <attr name="textSize"/><!--文字字体大小-->    </declare-styleable>

二、在View的构造方法中获得我们自定义的属性

public HistogramView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HistogramView);        maxSize = a.getFloat(R.styleable.HistogramView_maxSize, 100f);        cylinderWidth = a.getInt(R.styleable.HistogramView_cylinderWith, 50);        textSize = a.getDimensionPixelSize(R.styleable.RoundProgressBar_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,                12, getResources().getDisplayMetrics()));        cylinderColor = a.getColor(R.styleable.HistogramView_cylinderColor, 0xff40E0D0);        axesColor = a.getColor(R.styleable.HistogramView_axesColor, 0xffcdcdcd);        textColor = a.getColor(R.styleable.HistogramView_textColor, 0xffababab);        a.recycle();        initColorPaint();    }        private void initColorPaint() {        //设开始X坐标为0        startX = 0;        //设开始Y坐标为50        startY = 50;        //初始化柱状图画笔        mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mBarPaint.setColor(cylinderColor);        mBarPaint.setStyle(Paint.Style.FILL);        //初始化线的画笔        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mLinePaint.setStyle(Paint.Style.FILL);        mLinePaint.setColor(axesColor);        mLinePaint.setStrokeWidth(2);        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mTextPaint.setTextSize(textSize);        mTextPaint.setStrokeWidth(1);        mTextPaint.setColor(textColor);    }

三、重写onMeasure,处理一下wrapcontent问题

 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {//都是wrapcontent            setMeasuredDimension((int) maxSize, startY + 10 + histogramrNum * (cylinderWidth + 2 * 10));        } else if (widthSpecMode == MeasureSpec.AT_MOST) {//如果宽度为wrapcontent  高度为数值的时候            setMeasuredDimension((int) maxSize, heightSpecSize);// 宽度设置为maxSize        } else if (heightSpecMode == MeasureSpec.AT_MOST) { //如果宽度为数值的时候,高度为wrapcontent            setMeasuredDimension(widthSpecSize, startY + 10 + histogramrNum * (cylinderWidth + 2 * 10)); //高度为每条柱状图的宽度加上间距再乘以柱状图条数再加上开始Y值后得到的值        }    }

四、重写onLayout,在Ondraw之前获取对应的宽高

    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        measuredWidth = getMeasuredWidth();//获得测量后的宽度        measuredHeight = getMeasuredHeight();//获得测量后的高度        stopX = measuredWidth - cylinderWidth; //计算结束X的值        deltaX = (stopX - (startX + 7 * cylinderWidth / 5)) / verticalLineNum; //计算每条竖线之间的间距        deltaY = (measuredHeight - startY - cylinderWidth * histogramrNum) / histogramrNum; //计算每条柱状图之间的间距        numPerUnit = maxSize / verticalLineNum; //计算出每条竖线所代表的数值        currentHorizentalLineProgress = stopX;//初始化最上面横线的初始进度    }

五、进入最重要的正题了,重写onDraw,糖炒栗子啦。

首先画柱状图

画柱状图的方法就是使用canvas.drawRect(float left, float top, float right, float bottom, Paint paint)

 /**         * 画柱状图         */        for (int i = 0; i < histogramrNum; i++) {//for循环画出每一个柱状图            if (currentBarProgress[i] < (numList.get(i) / maxSize) * stopX) {            //这个for循环是为了一点点的画出增加感,就和progress差不多                currentBarProgress[i] += 5;                postInvalidateDelayed(10);            }            canvas.drawText(nameList.get(i), startX, startY + deltaY + i * (deltaY + cylinderWidth) + 3 * cylinderWidth / 4, mTextPaint);            canvas.drawRect(startX + 7 * cylinderWidth / 5, startY + deltaY + i * (deltaY + cylinderWidth), currentBarProgress[i], startY + deltaY + i * (deltaY + cylinderWidth) + cylinderWidth, mBarPaint);        }

接着画竖线和文字

有了上面画柱状图的思路,画竖线就非常容易想了,和画柱状图是一个思路,也是Activity中传入需要画几条竖线,然后在onDraw方法里分别去计算他们的当前进度值,然后再分别去画。

 /**         * 画竖线         */        for(int i=0 ; i<verticalLineNum ; i++){            if (currentVerticalLineProgress< measuredHeight) {                currentVerticalLineProgress+=3;                postInvalidateDelayed(10);            }            canvas.drawLine((startX+7*barWidth/5)+(i+1)*deltaX, startY, (startX+7*barWidth/5)+(i+1)*deltaX, currentVerticalLineProgress, mLinePaint);            //画文字            canvas.drawText(numPerUnit*(i+1)+unit, (startX+7*barWidth/5)+(i+1)*deltaX-barWidth, startY-barWidth/5, mTextPaint);        }

最后画顶部横线

/**         * 画最上面的横线         */        if (currentHorizentalLineProgress>startX+7*barWidth/5) {            currentHorizentalLineProgress-=10;            postInvalidateDelayed(10);        }        canvas.drawLine(stopX, startY, currentHorizentalLineProgress, startY, mLinePaint);    }

使用方法:

布局文件中:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_histogram"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.shanlovana.rcimageview.activities.HistogramActivity">    <TextView        android:id="@+id/textview"        android:layout_width="match_parent"        android:layout_height="30dp"        android:text="我公司盈利情况"        android:textColor="@color/colorAccent"        android:textSize="24sp"        />    <com.shanlovana.rcimageview.views.HistogramView        android:id="@+id/histogram_view"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_below="@+id/textview"        android:layout_marginTop="10dp"        app:axesColor="@color/colorAccent"        app:cylinderWith="40"        app:textColor="@color/colorPrimary"        app:textSize="20sp"        app:maxSize="10"        app:cylinderColor="#000000"        /></RelativeLayout>

Activity中:

public class HistogramActivity extends AppCompatActivity {    HistogramView mHistogramView;    private ArrayList<Float> numList;    private ArrayList<String> nameList;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_histogram);        mHistogramView = (HistogramView) findViewById(R.id.histogram_view);        // mPercentageBar= (PercentageBar) findViewById(R.id.percentageBar_view);        numList = new ArrayList<Float>();        nameList = new ArrayList<String>();        numList.add(7.0f);        numList.add(3.0f);        numList.add(4.0f);        numList.add(7.0f);        numList.add(4.0f);        numList.add(8.0f);        numList.add(9.0f);        numList.add(9.5f);        nameList.add("一");        nameList.add("二");        nameList.add("三");        nameList.add("四");        nameList.add("五");        nameList.add("六");        nameList.add("七");        nameList.add("八");        mHistogramView.setUnit("万");        mHistogramView.setNumListForEvery(numList);        mHistogramView.settNameListForEvery(nameList);    }}

效果图如下:

这个demo希望给你思路,还有已知的bug,文字的大小会影响柱状图的显示,会出现文字被柱状图压住,最近会修改。

源码因为这里github传不上去,回去传,到时候再发链接出来。

3 0
原创粉丝点击