厌伴老儒烹瓠叶,强随举子踏槐花。这篇文章主要讲述Android柱形图 绘制相关的知识,希望能为你提供帮助。
一直在维护www.halloandroid.com我的个人博客网站,发现漏了一篇没发在上面,补回来。上次写了一篇有关自定义折线图的文章,今天写一篇关于柱形图的文章,因为看了网上一位阿拉丁神灯大神的文章,所以自己也想动手写一个,熟练和学习一下自定义View。话不多说,开始撸!
文章图片
整体的思路:
画柱状图 –> 画竖线 –> 画顶部横线 –> 画文字
自定义View四步骤走起;还是我们自定View的那几个步骤:
- 1、自定义View的属性
- 2、在View的构造方法中获得我们自定义的属性
- [ 3、重写onMesure ]
- [ 4、重写onLayout ]
- 5、重写onDraw
<
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);
}
}
效果图如下:
文章图片
这个demo希望给你思路,还有已知的bug,文字的大小会影响柱状图的显示,会出现文字被柱状图压住,最近会修改。
源码因为这里github传不上去,回去传,到时候再发链接出来。
!--more-->
推荐阅读
- android的一些控件
- Android startActivities()的使用
- 用ng-view创建单页APP
- 如何使用隐写术在Python中隐藏图像中的秘密数据()
- 如何在Python中暴力破解SSH服务器(代码实现教程)
- 如何用Python在远程机器上执行Shell命令()
- 如何在Python中构建XSS漏洞扫描器(代码实现教程)
- 如何在Python中制作电子邮件提取器(代码实现教程)
- 如何使用hashlib在Python中使用哈希算法(详细教程)