您的位置:首页 > 移动开发 > Android开发

MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字

2017-04-20 17:14 3167 查看
本文出自:http://blog.csdn.net/dt235201314/article/details/70237777

Demo下载(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin




MPAndroidChart常见设置属性(一)——应用层 
MPAndroidChart项目实战(一)——实现对比性柱状图 
MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现 
MPAndroidChart项目实战(三)——饼状图实现和文字重合问题解决 
MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字 
MPAndroidChart X轴文字斜着显示 
MPAndroidChart项目实战(五)——组合图实现趋势图 
MPAndroidChart项目实战(六)——自定义1MPAndroidChart滑动冲突解决(搞不定产品设计师就只能搞自己) 
MPAndroidChart项目实战(七)——自定义横向柱状图 
MPAndroidChart项目实战(八)——自定义分段堆积柱状图 
MPAndroidChart项目实战(九)——自定义带文字分段堆积柱状图 


一丶慨述

虽然在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,运行代码,达到图二想要效果

五丶跪求关注下载源码,200粉小目标
欢迎关注我的博客及微信公众号,后面会给大家带来更多相关MPAndroidChart无法解决的仿MPAndroidChart图标自定义控件
源码下载记得顺便Star哦~
下载链接:https://github.com/JinBoy23520/MPAndroidChartDemoByJin
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: