Solución de problemas de esquinas redondeadas del gráfico de columnas de MPAndroidChart

Antecedentes y problemas

Se utilizan muchos gráficos en el proyecto, por lo que MPAndroidChart se utiliza como solución. Debo decir que esta biblioteca es muy poderosa. La mayoría de los requisitos del proyecto se pueden resolver directamente usando los métodos proporcionados por el proyecto, pero también hay algunos requisitos que requieren su propia personalización, como el tema de este artículo: el problema de las esquinas redondeadas de los histogramas.

solución

Para modificar mejor el código fuente para lograr los requisitos del proyecto, importo el proyecto importando el módulo, los detalles no se enumeran.

Nuestra diseñadora es muy delgada. El gráfico de columnas diseñado es así, con ángulos rectos en la parte inferior y esquinas redondeadas en la parte superior.

imagen.png

Al principio encontré esta solución para esquinas redondeadas: github.com/WW-Digital/…

El código aquí puede resolver el requisito de que las cuatro esquinas estén redondeadas. El núcleo es modificar el método de dibujo y cambiar el método de dibujo del lienzo de drawRect a drawRoundRect. Si el requisito es que las cuatro esquinas estén redondeadas, se puede usar esta solución y la cantidad de modificación del código no es grande.

El problema para mí es que no hay forma de dibujar esquinas redondeadas, por lo que esta solución no satisface mis necesidades. Continúe probando otras soluciones y encontró una solución para esquinas redondeadas parciales en esta pregunta: stackoverflow.com/questions/3…Según el código proporcionado por @duc tan , el requisito de esquinas redondeadas parciales se resolvió con éxito. convierte Rect en Path y lo dibuja a través de drawPath. Las esquinas redondeadas se pueden personalizar arbitrariamente modificando los siguientes parámetros del método.

roundRect(RectF rect, float rx, float ry, boolean tl, boolean tr, boolean br, boolean bl) 
复制代码

El problema parece estar resuelto, pero aún es cuadrado cuando está resaltado, lo que definitivamente no es posible, así que reescribí el drawHighlightedmétodo nuevamente e hice que el histograma resaltado también se redondeara parcialmente, y finalmente resolví este problema, el código es el siguiente :

@Override
public void drawHighlighted(Canvas c, Highlight[] indices) {
    BarData barData = mChart.getBarData();

    for (Highlight high : indices) {

        IBarDataSet set = barData.getDataSetByIndex(high.getDataSetIndex());

        if (set == null || !set.isHighlightEnabled()) {
            continue;
        }

        BarEntry e = set.getEntryForXValue(high.getX(), high.getY());

        if (!isInBoundsX(e, set)) {
            continue;
        }

        Transformer trans = mChart.getTransformer(set.getAxisDependency());

        mHighlightPaint.setColor(set.getHighLightColor());
        mHighlightPaint.setAlpha(set.getHighLightAlpha());

        boolean isStack = high.getStackIndex() >= 0 && e.isStacked();

        final float y1;
        final float y2;

        if (isStack) {

            if (mChart.isHighlightFullBarEnabled()) {

                y1 = e.getPositiveSum();
                y2 = -e.getNegativeSum();

            } else {

                Range range = e.getRanges()[high.getStackIndex()];

                y1 = range.from;
                y2 = range.to;
            }

        } else {
            y1 = e.getY();
            y2 = 0.f;
        }

        prepareBarHighlight(e.getX(), y1, y2, barData.getBarWidth() / 2f, trans);

        setHighlightDrawPos(high, mBarRect);

        Path path2 = roundRect(new RectF(mBarRect.left, mBarRect.top, mBarRect.right,
                mBarRect.bottom), mRadius, mRadius, true, true, false, false);

        c.drawPath(path2, mHighlightPaint);
    }
}
复制代码

Por último, publique el código y el uso de la clase de renderizador de la solución final.

public class CustomBarChartRender extends BarChartRenderer {
    private final RectF mBarShadowRectBuffer = new RectF();

    private int mRadius;

    public CustomBarChartRender(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
        super(chart, animator, viewPortHandler);
    }

    public void setRadius(int mRadius) {
        this.mRadius = mRadius;
    }

    @Override
    protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {

        Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
        mBarBorderPaint.setColor(dataSet.getBarBorderColor());
        mBarBorderPaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getBarBorderWidth()));
        mShadowPaint.setColor(dataSet.getBarShadowColor());
        boolean drawBorder = dataSet.getBarBorderWidth() > 0f;

        float phaseX = mAnimator.getPhaseX();
        float phaseY = mAnimator.getPhaseY();

        if (mChart.isDrawBarShadowEnabled()) {
            mShadowPaint.setColor(dataSet.getBarShadowColor());

            BarData barData = mChart.getBarData();

            float barWidth = barData.getBarWidth();
            float barWidthHalf = barWidth / 2.0f;
            float x;

            int i = 0;
            double count = Math.min(Math.ceil((int) (double) ((float) dataSet.getEntryCount() * phaseX)), dataSet.getEntryCount());
            while (i < count) {

                BarEntry e = dataSet.getEntryForIndex(i);

                x = e.getX();

                mBarShadowRectBuffer.left = x - barWidthHalf;
                mBarShadowRectBuffer.right = x + barWidthHalf;

                trans.rectValueToPixel(mBarShadowRectBuffer);

                if (!mViewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right)) {
                    i++;
                    continue;
                }

                if (!mViewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left)) {
                    break;
                }

                mBarShadowRectBuffer.top = mViewPortHandler.contentTop();
                mBarShadowRectBuffer.bottom = mViewPortHandler.contentBottom();

                c.drawRoundRect(mBarRect, mRadius, mRadius, mShadowPaint);
                i++;
            }
        }

        // initialize the buffer
        BarBuffer buffer = mBarBuffers[index];
        buffer.setPhases(phaseX, phaseY);
        buffer.setDataSet(index);
        buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
        buffer.setBarWidth(mChart.getBarData().getBarWidth());

        buffer.feed(dataSet);

        trans.pointValuesToPixel(buffer.buffer);

        boolean isSingleColor = dataSet.getColors().size() == 1;

        if (isSingleColor) {
            mRenderPaint.setColor(dataSet.getColor());
        }

        int j = 0;
        while (j < buffer.size()) {

            if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) {
                j += 4;
                continue;
            }

            if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j])) {
                break;
            }

            if (!isSingleColor) {
                // Set the color for the currently drawn value. If the index
                // is out of bounds, reuse colors.
                mRenderPaint.setColor(dataSet.getColor(j / 4));
            }

            Path path2 = roundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                    buffer.buffer[j + 3]), mRadius, mRadius, true, true, false, false);
            c.drawPath(path2, mRenderPaint);

            if (drawBorder) {
                Path path = roundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3]), mRadius, mRadius, true, true, false, false);
                c.drawPath(path, mBarBorderPaint);
            }
            j += 4;
        }

    }

    @Override
    public void drawHighlighted(Canvas c, Highlight[] indices) {
        BarData barData = mChart.getBarData();

        for (Highlight high : indices) {

            IBarDataSet set = barData.getDataSetByIndex(high.getDataSetIndex());

            if (set == null || !set.isHighlightEnabled()) {
                continue;
            }

            BarEntry e = set.getEntryForXValue(high.getX(), high.getY());

            if (!isInBoundsX(e, set)) {
                continue;
            }

            Transformer trans = mChart.getTransformer(set.getAxisDependency());

            mHighlightPaint.setColor(set.getHighLightColor());
            mHighlightPaint.setAlpha(set.getHighLightAlpha());

            boolean isStack = high.getStackIndex() >= 0 && e.isStacked();

            final float y1;
            final float y2;

            if (isStack) {

                if (mChart.isHighlightFullBarEnabled()) {

                    y1 = e.getPositiveSum();
                    y2 = -e.getNegativeSum();

                } else {

                    Range range = e.getRanges()[high.getStackIndex()];

                    y1 = range.from;
                    y2 = range.to;
                }

            } else {
                y1 = e.getY();
                y2 = 0.f;
            }

            prepareBarHighlight(e.getX(), y1, y2, barData.getBarWidth() / 2f, trans);

            setHighlightDrawPos(high, mBarRect);

            Path path2 = roundRect(new RectF(mBarRect.left, mBarRect.top, mBarRect.right,
                    mBarRect.bottom), mRadius, mRadius, true, true, false, false);

            c.drawPath(path2, mHighlightPaint);
        }
    }

    private Path roundRect(RectF rect, float rx, float ry, boolean tl, boolean tr, boolean br, boolean bl) {
        float top = rect.top;
        float left = rect.left;
        float right = rect.right;
        float bottom = rect.bottom;
        Path path = new Path();
        if (rx < 0) {
            rx = 0;
        }
        if (ry < 0) {
            ry = 0;
        }
        float width = right - left;
        float height = bottom - top;
        if (rx > width / 2) {
            rx = width / 2;
        }
        if (ry > height / 2) {
            ry = height / 2;
        }
        float widthMinusCorners = (width - (2 * rx));
        float heightMinusCorners = (height - (2 * ry));

        path.moveTo(right, top + ry);
        if (tr) {
            //top-right corner
            path.rQuadTo(0, -ry, -rx, -ry);
        } else {
            path.rLineTo(0, -ry);
            path.rLineTo(-rx, 0);
        }
        path.rLineTo(-widthMinusCorners, 0);
        if (tl) {
            //top-left corner
            path.rQuadTo(-rx, 0, -rx, ry);
        } else {
            path.rLineTo(-rx, 0);
            path.rLineTo(0, ry);
        }
        path.rLineTo(0, heightMinusCorners);

        if (bl) {
            //bottom-left corner
            path.rQuadTo(0, ry, rx, ry);
        } else {
            path.rLineTo(0, ry);
            path.rLineTo(rx, 0);
        }

        path.rLineTo(widthMinusCorners, 0);
        if (br) {
            //bottom-right corner
            path.rQuadTo(rx, 0, rx, -ry);
        } else {
            path.rLineTo(rx, 0);
            path.rLineTo(0, -ry);
        }

        path.rLineTo(0, -heightMinusCorners);

        path.close();//Given close, last lineto can be removed.

        return path;
    }
}
复制代码

Cómo usar (Kotlin):

val barChartRender = CustomBarChartRender(chart,chart.animator,chart.viewPortHandler)
barChartRender.setRadius(20)
barChart.renderer = barChartRender
复制代码

La captura de pantalla de la máquina real del efecto logrado es la siguiente:

imagen.png

Supongo que te gusta

Origin juejin.im/post/7100863388850503693
Recomendado
Clasificación