MPAndroidchart 圆形边缘用于彩色 HorizontalBarChart
Posted
技术标签:
【中文标题】MPAndroidchart 圆形边缘用于彩色 HorizontalBarChart【英文标题】:MPAndroidchart rounded edges for colorized HorizontalBarChart 【发布时间】:2016-05-08 19:08:21 【问题描述】:我想使用MPandroidChart 制作一个带有圆边的彩色HorizontalBarChart。我正在尝试为我的图表更改 HorizontalBarChartRenderer。这是我的代码:
HorizontalBarChart
初始化:
List<Float> values = new ArrayList<>();
List<Integer> colors = new ArrayList<>();
// initializing
float[] valuesArray = new float[values.size()];
for (int i = 0; i < values.size(); i++)
valuesArray[i] = values.get(i);
List<BarEntry> yValues = valuesArray.length <= 0
? Collections.<BarEntry>emptyList()
: Collections.singletonList(new BarEntry(valuesArray, 0));
BarDataSet barDataSet = new BarDataSet(yValues, "");
barDataSet.setColors(colors);
barDataSet.setValueFormatter(new ValueFormatter()
@Override
public String getFormattedValue(float value, Entry entry,
int dataSetIndex, ViewPortHandler viewPortHandler)
return "";
);
chartView.setData(new BarData(new String[]"sleep", barDataSet));
并扩展HorizontalBarChartRenderer
:
@Override
protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index)
// ...
c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1] + 10, buffer.buffer[j + 2], buffer.buffer[j + 3] - 10), 20, 20, mRenderPaint);
结果是:
如何只为外侧制作圆边? 像这样:
【问题讨论】:
【参考方案1】:我建议您在“正常”模式下绘制除最后一个之外的所有条形图,并首先绘制顶部(圆形)条形图,让它在所有条形图的整个长度上延伸。
这样,其他未圆角的条形将覆盖第一个绘制(圆形)条形底部不需要的圆角。
【讨论】:
【参考方案2】:我找到了解决方案。我的想法是像往常一样绘制数据,并在清除一些区域以使边缘变圆之后。 我的代码:
public class CircleHorizontalBarChartRenderer extends HorizontalBarChartRenderer
public CircleHorizontalBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler)
super(chart, animator, viewPortHandler);
@Override
protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index)
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
mShadowPaint.setColor(dataSet.getBarShadowColor());
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
// initialize the buffer
BarBuffer buffer = mBarBuffers[index];
buffer.setPhases(phaseX, phaseY);
buffer.setBarSpace(dataSet.getBarSpace());
buffer.setDataSet(index);
buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
buffer.feed(dataSet);
trans.pointValuesToPixel(buffer.buffer);
int length = buffer.buffer.length;
float left = 0;
float right = 0;
float top = buffer.buffer[length - 3];
float bot = buffer.buffer[length - 1];
boolean leftSaved = false;
for (int j = 0; j < buffer.size(); j += 4)
if (!mViewPortHandler.isInBoundsTop(buffer.buffer[j + 3]))
break;
if (!mViewPortHandler.isInBoundsBottom(buffer.buffer[j + 1]))
continue;
// Set the color for the currently drawn value.
// If the index is
// out of bounds, reuse colors.
int color = dataSet.getColor(j / 4);
mRenderPaint.setColor(color);
if (color != 0 && !leftSaved)
leftSaved = true;
left = buffer.buffer[j];
if (j > 4) // it works but its ugly
right = buffer.buffer[j - 2];
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1] + 10, buffer.buffer[j + 2],
buffer.buffer[j + 3] - 10, mRenderPaint);
Paint erasePaint = new Paint();
erasePaint.setAntiAlias(true);
erasePaint.setStyle(Paint.Style.STROKE);
int paintWidth = 20;
erasePaint.setStrokeWidth(paintWidth);
erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
c.drawRoundRect(new RectF(left - paintWidth / 2, top, right + paintWidth / 2, bot), 30, 30, erasePaint);
PorterDuff.Mode.CLEAR 仅在您将图层类型设置为软件时才有效。所以你需要打电话
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
用于 chartView 或其父视图。如果您不需要透明背景,并且已知背景颜色,您可以为erasePaint 设置此颜色,并且不要使用会降低性能的软件层类型。在这种情况下也不需要erasePaint.setXfermode。
最终结果:
【讨论】:
【参考方案3】:我编辑了 Nick Kober 的解决方案。这是代码;
public class CircleHorizontalBarChartRenderer extends HorizontalBarChartRenderer
public CircleHorizontalBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler)
super(chart, animator, viewPortHandler);
@Override
protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index)
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
mShadowPaint.setColor(dataSet.getBarShadowColor());
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
// initialize the buffer
BarBuffer buffer = mBarBuffers[index];
buffer.setPhases(phaseX, phaseY);
buffer.setBarWidth(dataSet.getBarBorderWidth());
buffer.setDataSet(index);
buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
buffer.feed(dataSet);
trans.pointValuesToPixel(buffer.buffer);
int timeToChange = buffer.size() / 4;
for (int j = 0; j < buffer.size(); j += 4)
if (!mViewPortHandler.isInBoundsTop(buffer.buffer[j + 3]))
break;
if (!mViewPortHandler.isInBoundsBottom(buffer.buffer[j + 1]))
continue;
// Set the color for the currently drawn value.
// If the index is
// out of bounds, reuse colors.
int color = dataSet.getColor(j / 4);
mRenderPaint.setColor(color);
if (j/4 == 0)
c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1] + 10, buffer.buffer[j+2], buffer.buffer[j + 3] - 10), 20, 20, mRenderPaint);
c.drawRect(new RectF(buffer.buffer[j] + 10 , buffer.buffer[j + 1] + 10, buffer.buffer[j+2], buffer.buffer[j + 3] - 10), mRenderPaint);
else if (j/4 < timeToChange - 1)
c.drawRect(new RectF(buffer.buffer[j] , buffer.buffer[j + 1] + 10, buffer.buffer[j+2], buffer.buffer[j + 3] - 10), mRenderPaint);
else if (j/4 == timeToChange - 1)
c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1] + 10, buffer.buffer[j+2], buffer.buffer[j + 3] - 10), 20, 20, mRenderPaint);
c.drawRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1] + 10, buffer.buffer[j+2] - 10, buffer.buffer[j + 3] - 10), mRenderPaint);
同样,您应该像 Nick 那样编写自己的自定义 Renderer 类。我添加了最后一部分(if-else if 块)。
我是这样想的,为第一条画圆角矩形。然后在上面通过将左侧移动到右侧来绘制一个矩形。通过移位,左侧保持圆形。对于内部的,将它们全部绘制为矩形。最后一个画圆角矩形。然后在其上方通过将右侧向左移动来绘制一个矩形。通过移位,右侧保持圆形。
我使用变量“timeToChange”来了解我当前正在绘制哪个条形图。
And the output is like this
【讨论】:
以上是关于MPAndroidchart 圆形边缘用于彩色 HorizontalBarChart的主要内容,如果未能解决你的问题,请参考以下文章
将圆形彩色背景应用于 Material PopupMenu 组件的正确方法是啥?