安卓的图表框架比较常用的有HelloChart和MPAndroidChart。HelloChart据说性能优化比较好,但是我根据我的个人经验,MPAndroidChart能实现的样式比较多。不得不说的是,在实际需求中,无论用哪个框架,把图表样式改得跟UI图一致都要费很大很大很大的力气。
当框架无法满足UI需求的效果时,就需要自定义了。以下是我绘制的图表效果:
下面贴代码:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import java.util.List;
/**
* 条形(圆角)图表控件。编写原因:图表框架无法符合UI需求
*
*/
public class BarChartView extends View {
private Paint mPaint;
private int mXAxisTextColor = convertColor("#9D9999");
private int mXAxisLineColor = convertColor("#231d1d26");
private int mBarColor = convertColor("#F6BF18");
private float mXAxisLineWidth = dp2px(0.5f);
private float mXAxisTextSize = dp2px(11.793f);
private float mXAxisLabelMarginTop = dp2px(8.844f);
private float mBarWidth = dp2px(4.913f);
private float mChartPaddingTop = dp2px(5.896f);
private float mChartPaddingLeft = dp2px(14.741f);
private int mMaxValue;
private List<String> mXAxisLabels;
private List<Integer> mXAxisValues;
public BarChartView(Context context) {
this(context, null);
}
public BarChartView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BarChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
//条形的起点
float barStartY = getHeight() - mXAxisTextSize - mXAxisLineWidth - mXAxisLabelMarginTop - mChartPaddingTop;
//画x轴文字
if (mXAxisLabels != null && mXAxisValues != null && mXAxisValues.size() == mXAxisLabels.size()) {
float delta = (getWidth() - mChartPaddingLeft * 2) / mXAxisLabels.size();
for (int i = 0, len = mXAxisLabels.size(); i < len; i++) {
mPaint.setColor(mXAxisTextColor);
mPaint.setTextSize(mXAxisTextSize);
mPaint.setStyle(Paint.Style.FILL);
if (i == len - 1) {
mPaint.setColor(Color.BLACK);
}
float textSize = mPaint.measureText(mXAxisLabels.get(i));
if (i == 0 && len > 12) {//月份视图,第一个X轴文本
canvas.drawText(mXAxisLabels.get(i), 0, getHeight() - mXAxisTextSize / 2, mPaint);
} else {
canvas.drawText(mXAxisLabels.get(i), i * delta + delta / 2 - textSize / 2 + mChartPaddingLeft, getHeight() - mXAxisTextSize / 2, mPaint);
}
//画条形
if (mMaxValue > 0) {//根据需求,下限(最小值)是0,固定的。
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setColor(mBarColor);
mPaint.setStrokeWidth(mBarWidth);
float positionX = i * delta + delta / 2 + mChartPaddingLeft;
canvas.drawLine(positionX, barStartY,
positionX, barStartY - (mXAxisValues.get(i) * 1.0f / mMaxValue * 1.0f * (barStartY-mChartPaddingTop)), mPaint);
}
}
}
//画x轴横线
mPaint.setStrokeWidth(mXAxisLineWidth);
mPaint.setColor(mXAxisLineColor);
canvas.drawLine(0, getHeight() - mXAxisLabelMarginTop - mXAxisTextSize, getWidth(), getHeight() - mXAxisTextSize - mXAxisLabelMarginTop, mPaint);
//画顶部的横线
canvas.drawLine(0, 0, getWidth(), 0, mPaint);
//画最小值
mPaint.setColor(mXAxisTextColor);
mPaint.setTextSize(mXAxisTextSize);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawText("0", getWidth() - mPaint.measureText("0"), barStartY, mPaint);
//画最大值
mPaint.setColor(mBarColor);
canvas.drawText(mMaxValue + "", getWidth() - mPaint.measureText(mMaxValue + ""), mChartPaddingTop + mXAxisTextSize / 2, mPaint);
}
public void setXAxisLabels(List<String> xAxisLabels) {
this.mXAxisLabels = xAxisLabels;
}
public void setXAxisValues(List<Integer> xAxisValues) {
this.mXAxisValues = xAxisValues;
this.mMaxValue = 0;
if (this.mXAxisValues != null) {
//求最大值
for (int item : mXAxisValues) {
if (item > this.mMaxValue) {
this.mMaxValue = item;
}
}
}
}
public void notifyDataSetChanged() {
invalidate();
}
public void setBarColor(int barColor) {
this.mBarColor = barColor;
}
private int convertColor(String colorStr) {
return Color.parseColor(colorStr);
}
private float dp2px(float dpVal) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
使用:
在xml里:
<BarChartView
android:id="@+id/chart"
android:layout_width="match_parent"
android:layout_height="200dp" />
给图表设置数据:
//周视图的数据
private void initWeekData() {
List<String> data = new ArrayList<>();
data.add("8月7日");
data.add("8");
data.add("9");
data.add("10");
data.add("11");
data.add("12");
data.add("13");
List<Integer> values = new ArrayList<>();
values.add(10);
values.add(1);
values.add(14);
values.add(3);
values.add(7);
values.add(0);
values.add(9);
setChartData(data, values);
}
//月视图的数据
private void initMonthData() {
List<String> data = new ArrayList<>();
data.add("7月16日");
for (int i = 17; i <= 31; i++) {
if (i == 20 || i == 26) {
data.add(i + "");
} else {
data.add("");
}
}
for (int i = 1; i <= 13; i++) {
if (i == 1 || i == 7 || i == 13) {
data.add(i + "");
} else {
data.add("");
}
}
List<Integer> values = new ArrayList<>();
for (int i = 0;i<data.size();i++){
values.add(new Random().nextInt(15));
}
setChartData(data, values);
}
//年视图的数据
private void initYearData() {
List<String> data = new ArrayList<>();
data.add("15年9月");
for (int i = 0; i <3; i++) {
data.add("");
}
for (int i = 1; i <= 8; i++) {
if (i == 1 || i == 5 || i == 8) {
data.add(i + "月");
} else {
data.add("");
}
}
List<Integer> values = new ArrayList<>();
for (int i = 0;i<data.size();i++){
values.add(new Random().nextInt(15));
}
setChartData(data, values);
}
private void setChartData(List<String> data, List<Integer> values) {
chart.setXAxisLabels(data);//X轴的文本
chart.setXAxisValues(values);//X轴对应的值
chart.setBarColor(0xff1BB3F9);//条形的颜色
chart.notifyDataSetChanged();
}