Android柱形图 绘制

厌伴老儒烹瓠叶,强随举子踏槐花。这篇文章主要讲述Android柱形图 绘制相关的知识,希望能为你提供帮助。

一直在维护www.halloandroid.com我的个人博客网站,发现漏了一篇没发在上面,补回来。
上次写了一篇有关自定义折线图的文章,今天写一篇关于柱形图的文章,因为看了网上一位阿拉丁神灯大神的文章,所以自己也想动手写一个,熟练和学习一下自定义View。话不多说,开始撸!
Android柱形图 绘制

文章图片

整体的思路:
画柱状图 –> 画竖线 –> 画顶部横线 –> 画文字

自定义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); }

接着画竖线和文字【Android柱形图 绘制】有了上面画柱状图的思路,画竖线就非常容易想了,和画柱状图是一个思路,也是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); } }

效果图如下:
Android柱形图 绘制

文章图片

这个demo希望给你思路,还有已知的bug,文字的大小会影响柱状图的显示,会出现文字被柱状图压住,最近会修改。
源码因为这里github传不上去,回去传,到时候再发链接出来。


    推荐阅读