我正在使用MPAndroidChart库,我的要求是以图片中给出的堆栈颜色显示堆栈值,也不是在栏上方,而是左右交替堆栈。
我试过这种方式,但它没有工作
set.setValueTextColors(colorList);
它为一个完整的酒吧提供一种颜色。
答案 0 :(得分:2)
我使用自定义渲染器来解决问题
这是代码
图表创建
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mp_android_stacked_bar_chart);
barChart = (BarChart) this.findViewById(R.id.bar_chart);
float[] val1 = {10, 20, 30, 40, 50, 60, 70};
float[] val2 = {70, 60, 50, 40, 30, 20, 10};
ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
for (int i = 0; i < val1.length; i++) {
yVals1.add(new BarEntry(i, new float[]{val1[i], val2[i]}));
}
barChart.getDescription().setEnabled(false);
barChart.setPinchZoom(false); // scaling can now only be done on x- and y-axis separately
barChart.setDrawGridBackground(false);
barChart.setDrawBarShadow(false);
barChart.setDrawValueAboveBar(true);
barChart.setHighlightFullBarEnabled(false);
barChart.getAxisRight().setEnabled(false);
YAxis yAxis = barChart.getAxisLeft(); // change the position of the y-labels
yAxis.setAxisMinimum(0f);
yAxis.setDrawGridLines(false);
XAxis xAxis = barChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setGranularity(1f);
xAxis.setDrawGridLines(false);
ArrayList<Integer> colorList = new ArrayList<>();
colorList.add(ContextCompat.getColor(this, R.color.colorPrimaryDark));
colorList.add(ContextCompat.getColor(this, R.color.colorAccent));
barChart.getLegend().setEnabled(false);
barChart.setRenderer(new StackedBarChartRenderer(barChart, barChart.getAnimator(), barChart.getViewPortHandler(), colorList));
BarDataSet set1 = new BarDataSet(yVals1, "");
set1.setColors(colorList);
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
BarData data = new BarData(dataSets);
barChart.setData(data);
barChart.setVisibleXRangeMaximum(4f);
barChart.invalidate();
}
这些是上述代码中的重要内容。这里我们为我们传递所需colorList
的图形设置我们自己的渲染器类 ArrayList<Integer> colorList = new ArrayList<>();
colorList.add(ContextCompat.getColor(this, R.color.colorPrimaryDark));
colorList.add(ContextCompat.getColor(this, R.color.colorAccent));
barChart.setRenderer(new StackedBarChartRenderer(barChart, barChart.getAnimator(), barChart.getViewPortHandler(), colorList));
<强>渲染器强>
public class StackedBarChartRenderer extends BarChartRenderer {
private ArrayList<Integer> colorList;
private int index = 0;
private int numOfColors;
public StackedBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Integer> colorList) {
super(chart, animator, viewPortHandler);
this.colorList = colorList;
this.numOfColors = colorList.size();
}
public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
mValuePaint.setColor(colorList.get(index));
if(value != 0){
c.drawText(formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x, y, mValuePaint);
}
index = ((index + 1) % (numOfColors));
}
}
在上面的代码中,我们重写了必要的方法,并以特定的方式遍历colorList。您可能需要更改逻辑 drawValue()函数以满足您的要求。
要详细了解自定义渲染器的工作原理,请查看此link
<强>结果强>
编辑
@Override
public void drawValues(Canvas c) {
// if values are drawn
if (isDrawingValuesAllowed(mChart)) {
List<IBarDataSet> dataSets = mChart.getBarData().getDataSets();
final float valueOffsetPlus = Utils.convertDpToPixel(4.5f);
float posOffset = 0f;
float negOffset = 0f;
boolean drawValueAboveBar = mChart.isDrawValueAboveBarEnabled();
for (int i = 0; i < mChart.getBarData().getDataSetCount(); i++) {
IBarDataSet dataSet = dataSets.get(i);
if (!shouldDrawValues(dataSet))
continue;
// apply the text-styling defined by the DataSet
applyValueTextStyle(dataSet);
boolean isInverted = mChart.isInverted(dataSet.getAxisDependency());
// calculate the correct offset depending on the draw position of
// the value
float valueTextHeight = Utils.calcTextHeight(mValuePaint, "8");
posOffset = (drawValueAboveBar ? -valueOffsetPlus : valueTextHeight + valueOffsetPlus);
negOffset = (drawValueAboveBar ? valueTextHeight + valueOffsetPlus : -valueOffsetPlus);
if (isInverted) {
posOffset = -posOffset - valueTextHeight;
negOffset = -negOffset - valueTextHeight;
}
// get the buffer
BarBuffer buffer = mBarBuffers[i];
final float phaseY = mAnimator.getPhaseY();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
// if only single values are drawn (sum)
if (!dataSet.isStacked()) {
for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
float x = (buffer.buffer[j] + buffer.buffer[j + 2]) / 2f;
if (!mViewPortHandler.isInBoundsRight(x))
break;
if (!mViewPortHandler.isInBoundsY(buffer.buffer[j + 1])
|| !mViewPortHandler.isInBoundsLeft(x))
continue;
BarEntry entry = dataSet.getEntryForIndex(j / 4);
float val = entry.getY();
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), val, entry, i, x,
val >= 0 ?
(buffer.buffer[j + 1] + posOffset) :
(buffer.buffer[j + 3] + negOffset),
dataSet.getValueTextColor(j / 4));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
Drawable icon = entry.getIcon();
float px = x;
float py = val >= 0 ?
(buffer.buffer[j + 1] + posOffset) :
(buffer.buffer[j + 3] + negOffset);
px += iconsOffset.x;
py += iconsOffset.y;
Utils.drawImage(
c,
icon,
(int)px,
(int)py,
icon.getIntrinsicWidth(),
icon.getIntrinsicHeight());
}
}
// if we have stacks
} else {
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
int bufferIndex = 0;
int index = 0;
while (index < dataSet.getEntryCount() * mAnimator.getPhaseX()) {
BarEntry entry = dataSet.getEntryForIndex(index);
float[] vals = entry.getYVals();
float x = (buffer.buffer[bufferIndex] + buffer.buffer[bufferIndex + 2]) / 2f;
int color = dataSet.getValueTextColor(index);
// we still draw stacked bars, but there is one
// non-stacked
// in between
if (vals == null) {
if (!mViewPortHandler.isInBoundsRight(x))
break;
if (!mViewPortHandler.isInBoundsY(buffer.buffer[bufferIndex + 1])
|| !mViewPortHandler.isInBoundsLeft(x))
continue;
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
buffer.buffer[bufferIndex + 1] +
(entry.getY() >= 0 ? posOffset : negOffset),
color);
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
Drawable icon = entry.getIcon();
float px = x;
float py = buffer.buffer[bufferIndex + 1] +
(entry.getY() >= 0 ? posOffset : negOffset);
px += iconsOffset.x;
py += iconsOffset.y;
Utils.drawImage(
c,
icon,
(int)px,
(int)py,
icon.getIntrinsicWidth(),
icon.getIntrinsicHeight());
}
// draw stack values
} else {
float[] transformed = new float[vals.length * 2];
float posY = 0f;
float negY = -entry.getNegativeSum();
for (int k = 0, idx = 0; k < transformed.length; k += 2, idx++) {
float value = vals[idx];
float y;
if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) {
// Take care of the situation of a 0.0 value, which overlaps a non-zero bar
y = value;
} else if (value >= 0.0f) {
posY += value;
y = posY;
} else {
y = negY;
negY -= value;
}
transformed[k + 1] = y * phaseY;
}
trans.pointValuesToPixel(transformed);
for (int k = 0; k < transformed.length; k += 2) {
final float val = vals[k / 2];
final boolean drawBelow =
(val == 0.0f && negY == 0.0f && posY > 0.0f) ||
val < 0.0f;
float y = transformed[k + 1]
+ (drawBelow ? negOffset : posOffset);
if (!mViewPortHandler.isInBoundsRight(x))
break;
if(val == 0){
drawValue(c,
dataSet.getValueFormatter(),
vals[k / 2],
entry,
i,
x,
y,
color);
}
if (!mViewPortHandler.isInBoundsY(y)
|| !mViewPortHandler.isInBoundsLeft(x))
continue;
if (dataSet.isDrawValuesEnabled()) {
drawValue(c,
dataSet.getValueFormatter(),
vals[k / 2],
entry,
i,
x,
y,
color);
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
Drawable icon = entry.getIcon();
Utils.drawImage(
c,
icon,
(int)(x + iconsOffset.x),
(int)(y + iconsOffset.y),
icon.getIntrinsicWidth(),
icon.getIntrinsicHeight());
}
}
}
bufferIndex = vals == null ? bufferIndex + 4 : bufferIndex + 4 * vals.length;
index++;
}
}
MPPointF.recycleInstance(iconsOffset);
}
}
}
将此功能添加到自定义渲染中,即使堆叠图中的某些值为0,也会选择正确的颜色。以上功能与以下部分的默认实现完全相同:
if(val == 0){
drawValue(c,
dataSet.getValueFormatter(),
vals[k / 2],
entry,
i,
x,
y,
color);
}