如何在 MPAndroidChart 中为每个柱放置自定义值图像?
How to put customized value&image per bar in MPAndroidChart?
背景
我正在使用 MPAndroidChart 来显示一个相对简单的条形图。
问题
有 2 项我需要设置,但我不知道如何自定义:
我需要为每个栏添加文本,而不是简单的值,它本身也有样式。
在每个栏的顶部,我需要放置覆盖其宽度的各种类型的可绘制对象(例如,一个栏中高度为 2dp 的蓝色,或另一个栏中具有相同高度的黄色渐变).
这是我需要做的演示:
我发现了什么
我检查了文档,但到目前为止我唯一发现的是使用 setDrawValueAboveBar
将值放在栏上方:
https://github.com/PhilJay/MPAndroidChart/wiki/Specific-Chart-Settings-&-Styling
我知道我也可以使用 setDrawIcons
添加图标,但这似乎不适用于应占据整个条宽的可绘制对象。
问题
如我所写,我想知道以上是否可行,以及如何实现:
如何在每个栏上方设置自定义的样式值?
如何在每个栏的顶部为 "sit" 设置不同的可绘制对象?
如果 #2 不可能(即使可能),是否可以将可绘制对象设置为栏本身?例如,有些条形图是纯灰色,有些条形图是渐变黄色?
您需要自定义条形图 BarChartRenderer 才能实现此目的。我提供了一个粗略的样本。希望对你有帮助。
条形图设置代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// custom colors that you want on top of the bars
ArrayList<Integer> myColors = new ArrayList<>();
myColors.add(Color.BLACK);
myColors.add(Color.YELLOW);
myColors.add(Color.BLUE);
myColors.add(Color.DKGRAY);
myColors.add(Color.GREEN);
myColors.add(Color.GRAY);
String[] myText = {"A Round", "B Round", "C Round", "D Round", "E Round", "F Round"};
BarChart mChart = (BarChart) findViewById(R.id.barChart);
mChart.setDrawBarShadow(false);
mChart.getDescription().setEnabled(false);
mChart.setDrawGridBackground(false);
XAxis xaxis = mChart.getXAxis();
xaxis.setDrawGridLines(false);
xaxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xaxis.setDrawLabels(true);
xaxis.setDrawAxisLine(false);
YAxis yAxisLeft = mChart.getAxisLeft();
yAxisLeft.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
yAxisLeft.setDrawGridLines(false);
yAxisLeft.setDrawAxisLine(false);
yAxisLeft.setEnabled(false);
mChart.getAxisRight().setEnabled(false);
// set your custom renderer
mChart.setRenderer(new BarChartCustomRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler(), myColors));
mChart.setDrawValueAboveBar(true);
Legend legend = mChart.getLegend();
legend.setEnabled(false);
ArrayList<BarEntry> valueSet1 = new ArrayList<BarEntry>();
for (int i = 0; i < 6; ++i) {
BarEntry entry = new BarEntry(i, (i + 1) * 10);
valueSet1.add(entry);
}
List<IBarDataSet> dataSets = new ArrayList<>();
BarDataSet barDataSet = new BarDataSet(valueSet1, " ");
barDataSet.setValueFormatter(new MyFormatter(myText));
barDataSet.setColor(Color.CYAN);
dataSets.add(barDataSet);
BarData data = new BarData(dataSets);
mChart.setData(data);
}
public class MyFormatter implements IValueFormatter {
String[] text;
public MyFormatter(String[] text) {
this.text = text;
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return String.valueOf((int)value)+"M" + ", " + text[(int) entry.getX()];
}
}
}
自定义渲染器
public class BarChartCustomRenderer extends BarChartRenderer {
private Paint myPaint;
private ArrayList<Integer> myColors;
public BarChartCustomRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Integer> myColors) {
super(chart, animator, viewPortHandler);
this.myPaint = new Paint();
this.myColors = myColors;
}
@Override
public void drawValues(Canvas c) {
super.drawValues(c);
// you can modify the original method
// so that everything is drawn on the canvas inside a single loop
// also you can add logic here to meet your requirements
int colorIndex = 0;
for (int i = 0; i < mChart.getBarData().getDataSetCount(); i++) {
BarBuffer buffer = mBarBuffers[i];
float left, right, top, bottom;
for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
myPaint.setColor(myColors.get(colorIndex++));
left = buffer.buffer[j];
right = buffer.buffer[j + 2];
top = buffer.buffer[j + 1];
bottom = buffer.buffer[j + 3];
// myPaint.setShader(new LinearGradient(left,top,right,bottom, Color.CYAN, myColors.get(colorIndex++), Shader.TileMode.MIRROR ));
c.drawRect(left, top, right, top+5f, myPaint);
}
}
}
@Override
public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
String text = formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler);
String[] splitText;
if(text.contains(",")){
splitText = text.split(",");
Paint paintStyleOne = new Paint(mValuePaint);
Paint paintStyleTwo = new Paint(mValuePaint);
paintStyleOne.setColor(Color.BLACK);
paintStyleTwo.setColor(Color.BLUE);
c.drawText(splitText[0], x, y-20f, paintStyleOne);
c.drawText(splitText[1], x, y, paintStyleTwo);
}
//else{
// super.drawValue(c, formatter, value, entry, dataSetIndex, x, y, color);
//}
}
}
结果
你也可以通过稍微修改自定义渲染器来为整个栏做一个渐变效果:
myPaint.setShader(new LinearGradient(left,top,right,bottom, Color.CYAN, myColors.get(colorIndex++), Shader.TileMode.MIRROR ));
c.drawRect(left, top, right, bottom, myPaint);
您可以使用自定义渲染器类似地绘制和设置文本样式。
检查 以了解有关自定义渲染器的更多信息。
使用可绘制对象代替颜色的更新
//get bitmap from a drawable
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.myDrawable);
之后您可以创建位图列表并将其传递到渲染器而不是颜色列表。
如果你只想在栏的顶部绘制,你可以使用这个:
c.drawBitmap(bitmap.get(index++), null, new RectF(left, top, right, top+5f), null);
或者如果你想覆盖整个条形图,你可以像这样使用位图来实现:
c.drawBitmap(bitmap.get(index++), null, new RectF(left, top, right, bottom), null);
背景
我正在使用 MPAndroidChart 来显示一个相对简单的条形图。
问题
有 2 项我需要设置,但我不知道如何自定义:
我需要为每个栏添加文本,而不是简单的值,它本身也有样式。
在每个栏的顶部,我需要放置覆盖其宽度的各种类型的可绘制对象(例如,一个栏中高度为 2dp 的蓝色,或另一个栏中具有相同高度的黄色渐变).
这是我需要做的演示:
我发现了什么
我检查了文档,但到目前为止我唯一发现的是使用
setDrawValueAboveBar
将值放在栏上方: https://github.com/PhilJay/MPAndroidChart/wiki/Specific-Chart-Settings-&-Styling我知道我也可以使用
setDrawIcons
添加图标,但这似乎不适用于应占据整个条宽的可绘制对象。
问题
如我所写,我想知道以上是否可行,以及如何实现:
如何在每个栏上方设置自定义的样式值?
如何在每个栏的顶部为 "sit" 设置不同的可绘制对象?
如果 #2 不可能(即使可能),是否可以将可绘制对象设置为栏本身?例如,有些条形图是纯灰色,有些条形图是渐变黄色?
您需要自定义条形图 BarChartRenderer 才能实现此目的。我提供了一个粗略的样本。希望对你有帮助。
条形图设置代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// custom colors that you want on top of the bars
ArrayList<Integer> myColors = new ArrayList<>();
myColors.add(Color.BLACK);
myColors.add(Color.YELLOW);
myColors.add(Color.BLUE);
myColors.add(Color.DKGRAY);
myColors.add(Color.GREEN);
myColors.add(Color.GRAY);
String[] myText = {"A Round", "B Round", "C Round", "D Round", "E Round", "F Round"};
BarChart mChart = (BarChart) findViewById(R.id.barChart);
mChart.setDrawBarShadow(false);
mChart.getDescription().setEnabled(false);
mChart.setDrawGridBackground(false);
XAxis xaxis = mChart.getXAxis();
xaxis.setDrawGridLines(false);
xaxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xaxis.setDrawLabels(true);
xaxis.setDrawAxisLine(false);
YAxis yAxisLeft = mChart.getAxisLeft();
yAxisLeft.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
yAxisLeft.setDrawGridLines(false);
yAxisLeft.setDrawAxisLine(false);
yAxisLeft.setEnabled(false);
mChart.getAxisRight().setEnabled(false);
// set your custom renderer
mChart.setRenderer(new BarChartCustomRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler(), myColors));
mChart.setDrawValueAboveBar(true);
Legend legend = mChart.getLegend();
legend.setEnabled(false);
ArrayList<BarEntry> valueSet1 = new ArrayList<BarEntry>();
for (int i = 0; i < 6; ++i) {
BarEntry entry = new BarEntry(i, (i + 1) * 10);
valueSet1.add(entry);
}
List<IBarDataSet> dataSets = new ArrayList<>();
BarDataSet barDataSet = new BarDataSet(valueSet1, " ");
barDataSet.setValueFormatter(new MyFormatter(myText));
barDataSet.setColor(Color.CYAN);
dataSets.add(barDataSet);
BarData data = new BarData(dataSets);
mChart.setData(data);
}
public class MyFormatter implements IValueFormatter {
String[] text;
public MyFormatter(String[] text) {
this.text = text;
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return String.valueOf((int)value)+"M" + ", " + text[(int) entry.getX()];
}
}
}
自定义渲染器
public class BarChartCustomRenderer extends BarChartRenderer {
private Paint myPaint;
private ArrayList<Integer> myColors;
public BarChartCustomRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Integer> myColors) {
super(chart, animator, viewPortHandler);
this.myPaint = new Paint();
this.myColors = myColors;
}
@Override
public void drawValues(Canvas c) {
super.drawValues(c);
// you can modify the original method
// so that everything is drawn on the canvas inside a single loop
// also you can add logic here to meet your requirements
int colorIndex = 0;
for (int i = 0; i < mChart.getBarData().getDataSetCount(); i++) {
BarBuffer buffer = mBarBuffers[i];
float left, right, top, bottom;
for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
myPaint.setColor(myColors.get(colorIndex++));
left = buffer.buffer[j];
right = buffer.buffer[j + 2];
top = buffer.buffer[j + 1];
bottom = buffer.buffer[j + 3];
// myPaint.setShader(new LinearGradient(left,top,right,bottom, Color.CYAN, myColors.get(colorIndex++), Shader.TileMode.MIRROR ));
c.drawRect(left, top, right, top+5f, myPaint);
}
}
}
@Override
public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
String text = formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler);
String[] splitText;
if(text.contains(",")){
splitText = text.split(",");
Paint paintStyleOne = new Paint(mValuePaint);
Paint paintStyleTwo = new Paint(mValuePaint);
paintStyleOne.setColor(Color.BLACK);
paintStyleTwo.setColor(Color.BLUE);
c.drawText(splitText[0], x, y-20f, paintStyleOne);
c.drawText(splitText[1], x, y, paintStyleTwo);
}
//else{
// super.drawValue(c, formatter, value, entry, dataSetIndex, x, y, color);
//}
}
}
结果
你也可以通过稍微修改自定义渲染器来为整个栏做一个渐变效果:
myPaint.setShader(new LinearGradient(left,top,right,bottom, Color.CYAN, myColors.get(colorIndex++), Shader.TileMode.MIRROR ));
c.drawRect(left, top, right, bottom, myPaint);
您可以使用自定义渲染器类似地绘制和设置文本样式。
检查
使用可绘制对象代替颜色的更新
//get bitmap from a drawable
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.myDrawable);
之后您可以创建位图列表并将其传递到渲染器而不是颜色列表。
如果你只想在栏的顶部绘制,你可以使用这个:
c.drawBitmap(bitmap.get(index++), null, new RectF(left, top, right, top+5f), null);
或者如果你想覆盖整个条形图,你可以像这样使用位图来实现:
c.drawBitmap(bitmap.get(index++), null, new RectF(left, top, right, bottom), null);