【问题标题】:How to put customized value&image per bar in MPAndroidChart?如何在 MPAndroidChart 中放置自定义值和图像?
【发布时间】:2018-03-14 14:19:20
【问题描述】:

背景

我正在使用 MPAndroidChart 来显示一个相对简单的条形图。

问题

我需要设置两件事,但我不知道如何自定义:

  1. 我需要为每个条添加文本,而不是简单的值,它本身也有样式。

  2. 在每个条的顶部,我需要放置在宽度上覆盖它的各种类型的可绘制对象(例如,一个条中高度为 2dp 的蓝色,或另一个条中具有相同高度的黄色渐变)。

这是我需要做的演示:

我发现了什么

  1. 我检查了文档,但到目前为止我发现的唯一一件事就是将值放在栏上方,使用 setDrawValueAboveBarhttps://github.com/PhilJay/MPAndroidChart/wiki/Specific-Chart-Settings-&-Styling

  2. 我知道我也可以通过使用 setDrawIcons 添加图标,但这似乎不适用于应该占据整个条宽的可绘制对象。

问题

正如我所写,我想知道上述是否可行,以及如何:

  1. 如何在每个条形上方设置自定义的样式值?

  2. 如何设置不同的可绘制对象以“坐在”每个栏的顶部?

  3. 如果 #2 是不可能的(甚至可能是),是否可以将可绘制对象设置为条本身?例如,一些条形图是纯灰色,而一些条形图有渐变黄色可绘制?

【问题讨论】:

    标签: android bar-chart mpandroidchart


    【解决方案1】:

    您需要自定义条形图 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);
    

    您可以使用自定义渲染器类似地绘制和设置文本样式。 查看this 了解有关自定义渲染器的更多信息。

    使用drawables代替颜色的更新

    //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);
    

    【讨论】:

    • 会检查的。但是文本(在条形上方)呢?
    • 好的,我已经测试过了。似乎运作良好。如何设置上部的可绘制对象(我已经询问了可绘制对象,而不仅仅是颜色,甚至在屏幕截图上......)?我注意到你在那里只使用了颜色(myColors)。您拨打setDrawValueAboveBar 两次。一次为假,一次为真。另外,顺便说一句,我认为对于drawValue,您应该避免创建新对象。您可以使用字段中的 Paint 实例。
    • 是的 setDrawValueAboveBar 应该只被调用一次并且为真。我也同意你不创建新的油漆对象的建议。至于使用drawables而不是颜色,您可以传递一个位图列表而不是颜色,并按如下方式使用它们:c.drawBitmap(bitmap.get(index++), null, new RectF(left, top, right, top+5f), null);
    • 但如果您只使用纯色或渐变色,那么只使用颜色而不使用可绘制对象不是更容易吗?这样您就不必担心扩展问题
    • 缩放应该不是问题。无论如何它应该很小。是否可以改为设置可绘制对象?
    猜你喜欢
    • 2017-04-09
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多