MPAndroidChart项目实战(四)——柱状图实现及X轴文
我的CSDN:http://blog.csdn.net/dt235201314/article/details/70237777
Demo下载(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin
一丶慨述
虽然在MPAndroidChart项目实战(一)里面就说了双柱状图的实现,但毕竟那是旧的jar包版,而目前的项目开发,用到的都是新版本,所以还是说一下总结一下,不整理不知道,一整理吓一跳,问题还真不少。
二丶效果:
三丶实现功能
1.实现柱状图。
2.解决柱状图上换行拼接文字问题。
3.解决X轴文字偶尔不显示问题。
四丶看代码
1.项目复用率很高,先得有个BarChartEntry.Java
/**
* 柱状图
* Created by jin
*/
public class BarChartEntity extends BaseChartEntity<BarEntry> {
public BarChartEntity(BarLineChartBase chart, List<BarEntry>[] entries, String[] labels, int[] chartColor, int valueColor, float textSize) {
super(chart, entries, labels, chartColor, valueColor, textSize);
}
@Override
protected void initChart() {
super.initChart();
mChart.getAxisLeft().setDrawGridLines(true);
mChart.getAxisLeft().enableGridDashedLine(10f, 15f, 0f);
mChart.getAxisLeft().setGridLineWidth(0.5f);
mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
mChart.getAxisLeft().setDrawZeroLine(false);
mChart.getAxisRight().setDrawZeroLine(false);
mChart.getAxisRight().setZeroLineWidth(0f);
mChart.getAxisLeft().setZeroLineWidth(0f);
mChart.getAxisLeft().setDrawAxisLine(false);
mChart.getXAxis().setDrawAxisLine(false);
mChart.getXAxis().setAxisMinimum(0);
}
@Override
protected void setChartData() {
BarDataSet barDataSet;
if (mChart.getData() != null && mChart.getData().getDataSetCount() > 0) {
barDataSet = (BarDataSet) mChart.getData().getDataSetByIndex(0);
barDataSet.setValues(mEntries[0]);
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
} else {
barDataSet = new BarDataSet(mEntries[0], labels == null ? "" : labels[0]);
barDataSet.setColors(mChartColors);
List<Integer> colors = new ArrayList<>();
for (int color : mChartColors) {
colors.add(color);
}
barDataSet.setValueTextColors(colors);
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(barDataSet);
BarData data = new BarData(dataSets);
data.setValueTextSize(mTextSize);
data.setBarWidth(0.9f);
mChart.setData(data);
}
}
public void setDrawValueAboveBar(boolean aboveBar) {
((BarChart)mChart).setDrawValueAboveBar(aboveBar);
}
/**
* <p>设置bar宽度</p>
* @param barWidth float
*/
public void setBarWidth(float barWidth) {
((BarChart)mChart).getData().setBarWidth(barWidth);
}
}
这样就可以直接添加方法用了
/**
* 柱状图 该在X轴得文字显示在柱状图上
*/
private void updataBarChart() {
mBarChart = (BarChart) mView.findViewById(R.id.new_the_bar_chart);
List<BarEntry>[] entries = new ArrayList[3];
final String[] labels = {
getActivity().getResources().getString(R.string.actual_value),
getActivity().getResources().getString(R.string.budget_value),
getActivity().getResources().getString(R.string.yoy_value),};
int[] cahrtColors = {
Color.parseColor("#45A2FF"),
Color.parseColor("#58D4C5"),
Color.parseColor("#FDB25F")};
final double[] values = new double[3];
ArrayList<BarEntry> entries1 = new ArrayList<>();
float actualValue = 10086;
float budgetValue = 1001;
float yoyValue = 12580;
entries1.add(new BarEntry(0.5f, actualValue));
entries1.add(new BarEntry(1.3f, budgetValue));
entries1.add(new BarEntry(2.1f, yoyValue));
values[0] = actualValue;
values[1] = budgetValue;
values[2] = yoyValue;
entries[0] = entries1;
if (mBarChart.getData() != null) {
mBarChart.getData().clearValues();
}
BarChartEntity barChartEntity = new BarChartEntity(mBarChart, entries, labels, cahrtColors, Color.parseColor("#999999"), 13f);
barChartEntity.setBarWidth(0.55f);
barChartEntity.setDrawValueAboveBar(true);
mBarChart.setPinchZoom(false);
mBarChart.setScaleEnabled(false);
mBarChart.animateY(2000, Easing.EasingOption.EaseInOutQuart);
barChartEntity.setAxisFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return "";
}
}, null);
mBarChart.getLegend().setEnabled(false);
/**
* 拼接柱状图上文字,涉及到修改源码
*/
mBarChart.getData().setValueFormatter(new IValueFormatter() {
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return labels[entry.getX() == 0.5f ? 0 : (entry.getX() == 1.3f ? 1 : 2)]
+ "\n"
+ mFormat.format(values[entry.getX() == 0.5f ? 0 : (entry.getX() == 1.3f ? 1 : 2)]);
}
});
/**
* 处理当数据都为0,不好看情况
*/
float yMax = mBarChart.getData().getYMax() == 0 ? 100f : mBarChart.getData().getYMax();
float delta = yMax / 5.5f;
mBarChart.getAxisLeft().setAxisMaximum(yMax + delta);
float yMin = mBarChart.getData().getYMin();
if (yMin == 0) {
yMin = 0;
}
float deltaMin = yMin / 5.0f;
mBarChart.getAxisLeft().setAxisMinimum(yMin - deltaMin);
}
代码敲完,发现没报错,但问题了来,柱状图上的文字是在同一排显,方法getFormattedValue里的“\n”,换行符并没起到作用。
此刻埋怨(该死的设计师,把那行字写在X轴出不久OK,非要整在柱状图上),初级工程师满心抓狂,大神微微一下,可能是绘图的部分出问题,找到位置
方法 public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color){}用到的是paint,是不支持换行符的,那么怎么办呢,换支持的textpaint。
/**
* Draws the value of the given entry by using the provided IValueFormatter.
*
* @param c canvas
* @param formatter formatter for custom value-formatting
* @param value the value to be drawn
* @param entry the entry the value belongs to
* @param dataSetIndex the index of the DataSet the drawn Entry belongs to
* @param x position
* @param y position
* @param color
*/
public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
mValuePaint.setColor(color);
//回车换行符处理
TextPaint textPaint = new TextPaint();
textPaint.setColor(mValuePaint.getColor());
textPaint.setTextSize(mValuePaint.getTextSize());
textPaint.setAntiAlias(true);
String valueTemp = formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler);
StaticLayout myStaticLayout = new StaticLayout(valueTemp, 0, valueTemp.length(), textPaint,
(int)textPaint.measureText(valueTemp), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
c.save();
c.translate(x - myStaticLayout.getWidth() / 2, y - myStaticLayout.getHeight()); //开始画位置
myStaticLayout.draw(c);
c.restore();
// c.drawText(formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x, y, mValuePaint);
}
问题解决了。菜鸟此刻仰望大神,我要怎么才能像大神一样,大神微微一小:“恶补Android 绘图部分,多读源码,Believe you can fly”
菜鸟恍然大悟,原来设计师并不是刁难自己,原来是磨练啊。
说完X轴文字放到柱状图上的,再说说,X轴显示时间段的。
看方法:
/**
* X轴显示时间段的柱状图
*/
public void updataXBarChart(){
final MonthItemEntity entity = new MonthItemEntity();
xBarChart = (BarChart) mView.findViewById(R.id.new_x_bar_chart);
List<BarEntry>[]entries = new ArrayList[1];
//x轴坐标 控制显示位置,并不会在X轴上显示具体的值
final float[] xlabels = new float[entity.getMonthDatas().size()];
int[] color ={Color.parseColor("#7f45a2ff")};
final String unit = "%";
//x轴坐标增量
float delta = 1;
for (int index = 0, len = entity.getMonthDatas().size(); index < len; index ++) {
xlabels[index] = index * delta + delta;
}
entries[0] = entity.getMonthEntries();
BarChartEntity barChartEntity = new BarChartEntity(xBarChart, entries, null, color, Color.parseColor("#999999"), 10f);
/*属性修改设置*/
barChartEntity.setBarWidth(0.55f);
barChartEntity.setDrawValueAboveBar(true);
xBarChart.setPinchZoom(false);
xBarChart.setScaleEnabled(false);
xBarChart.getLegend().setEnabled(false);
xBarChart.getXAxis().setTextSize(9f);
xBarChart.getAxisLeft().setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
mBarChart.animateY(1000, Easing.EasingOption.EaseInOutQuart);
/*X,Y坐标显示设置*/
barChartEntity.setAxisFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
for (int index = 0,len = xlabels.length; index < len; index ++) {
if (value == xlabels[index]) {
return entity.getMonthDatas().get(index).getBeginTime() + "-" + entity.getMonthDatas().get(index).getEndTime();
}
}
return "";
}
}, new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return mFormat.format(value) + (unit.equals("%") ? unit : "");
}
});
/*值显示设置*/
xBarChart.getData().setValueFormatter(new IValueFormatter() {
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return mFormat.format(value) + (unit.equals("%") ? unit : "");
}
});
/*Y轴最大值最小值设置,为了尽可能的显示完整数据*/
float yMax = xBarChart.getData().getYMax() == 0 ? 100f :xBarChart.getData().getYMax();
float yDelta = yMax / 5.5f;
float axisMaximum = yMax + yDelta;
if (axisMaximum < 5) {
axisMaximum = 5;
}
xBarChart.getAxisLeft().setAxisMaximum(axisMaximum);
float yMin = xBarChart.getData().getYMin();
float deltaMin = yMin / 5.0f;
xBarChart.getAxisLeft().setAxisMinimum(yMin - deltaMin);
}
理论上这样就OK了,设置了根据方法设置了XY的显示,然而X轴得文字去有一写无法显示,如效果图一。
这下有gg了,没时间还怎么用,找大神,这下大神也笑不出来了:“待我细细研究再做讨论”......
第二天,大神微微一笑,先看在显示X轴字符样式的方法里面的判断if (value == xlabels[index]),为什么我要这么去判断呢。我们知道X轴的值在显示上是平均分的,而我只有三个柱子的时候,我只要他显示三个值,所以用了xlabels[index]作为对比,只在整数位置显示拼接文字。那么问题又来了。X轴得Value是的浮点型,这样计算出柱子的平均位置就可能是浮点型,不等了自然就不显示。好了,改。
找到位置:
方法computeAxisValues(),把计算值改为int型
主要修改位置(截了修改位置的代码):
protected void computeAxisValues(float min, float max) {
float yMin = min;
float yMax = max;
int labelCount = mAxis.getLabelCount();
double range = Math.abs(yMax - yMin);
if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
mAxis.mEntries = new float[]{};
mAxis.mCenteredEntries = new float[]{};
mAxis.mEntryCount = 0;
return;
}
// Find out how much spacing (in y value space) between axis values
int rawInterval = (int)range / labelCount;
int interval = (int)Utils.roundToNextSignificant(rawInterval);
if (interval == 0) {
interval +=1;
}
// If granularity is enabled, then do not allow the interval to go below specified granularity.
// This is used to avoid repeated values when rounding values for display.
if (mAxis.isGranularityEnabled())
interval = interval < mAxis.getGranularity() ? (int)mAxis.getGranularity() : interval;
// Normalize interval
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or
// 90
interval = (int)Math.floor(10 * intervalMagnitude);
}
int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;
// force label count
if (mAxis.isForceLabelsEnabled()) {
interval = (int) range / (int) (labelCount - 1);
mAxis.mEntryCount = labelCount;
if (mAxis.mEntries.length < labelCount) {
// Ensure stops contains at least numStops elements.
mAxis.mEntries = new float[labelCount];
}
OK,运行代码,达到图二想要效果
就写到这里,代码以上传,谢谢收看,如有帮助可以顺手star一下,顺便关注一下博主哦。