I used a custom renderer to fix the issue
Here is the code
Chart creation
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();
}
These are important lines in the above code. Here we are setting the our own renderer class for the graph where we pass the required 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));
RENDERER
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));
}
}
In the above code we are overriding the necessary methods and iterating through the colorList in a cicular manner. You may have to change the logic
of the drawValue() function to suit your requirements.
To know more about how custom renderer works, check this link
Result

EDIT
@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);
}
}
}
Add this function to your custom render pick up the proper color even if some of your values are 0 in the stacked graph. This above function is exactly same as the default implementation expect for the following part :
if(val == 0){
drawValue(c,
dataSet.getValueFormatter(),
vals[k / 2],
entry,
i,
x,
y,
color);
}