At the beginning. My bar chart looks something like this

But the prototype from the product looks like thisSome bar charts have a rounded corner at the top. All of the requirements are done except for this rounded corner

After a quick Internet search, Github CSDN briefly noted that other blogs have found a better way to do it than I did. Do you really want to change the source code? Then he continued his search. Finally despair. To change the source code!

Look all over the Internet. The drawDataSet method under the BarChartRenderer class is finally located to draw the bar graph, so we need to rewrite this method and define a class of our own. Used to rewrite source code

So I’m going to create SuddleBarChartRenderer class in here

import android.graphics.Canvas
import android.graphics.Path
import android.graphics.RectF
import com.github.mikephil.charting.animation.ChartAnimator
import com.github.mikephil.charting.highlight.Highlight
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet
import com.github.mikephil.charting.renderer.BarChartRenderer
import com.github.mikephil.charting.utils.Utils
import com.github.mikephil.charting.utils.ViewPortHandler


class SuddleBarChartRenderer( chart: BarDataProvider? , animator: ChartAnimator? , viewPortHandler: ViewPortHandler? ) :
    BarChartRenderer(chart, animator, viewPortHandler) {
    val mBarShadowRectBuffer = RectF()
    override fun drawDataSet(c: Canvas, dataSet: IBarDataSet, index: Int) {
        val trans = mChart.getTransformer(dataSet.axisDependency)

        mBarBorderPaint.color = dataSet.barBorderColor
        mBarBorderPaint.strokeWidth = Utils.convertDpToPixel(dataSet.barBorderWidth)

        val drawBorder = dataSet.barBorderWidth > 0f

        val phaseX = mAnimator.phaseX
        val phaseY = mAnimator.phaseY

        // draw the bar shadow before the values

        // draw the bar shadow before the values
        if (mChart.isDrawBarShadowEnabled) {
            mShadowPaint.color = dataSet.barShadowColor
            val barData = mChart.barData
            val barWidth = barData.barWidth
            val barWidthHalf = barWidth / 2.0 f
            var x: Float
            var i = 0
            val count = Math.min(
                Math.ceil((dataSet.entryCount.toFloat() * phaseX).toDouble()).toInt(),
                dataSet.entryCount
            )
            while (i < count) {
                val e = dataSet.getEntryForIndex(i)
                x = e.x
                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.drawRect(mBarShadowRectBuffer, mShadowPaint)
                i++
            }
        }

        // initialize the buffer

        // initialize the buffer
        val buffer = mBarBuffers[index]
        buffer.setPhases(phaseX, phaseY)
        buffer.setDataSet(index)
        buffer.setInverted(mChart.isInverted(dataSet.axisDependency))
        buffer.setBarWidth(mChart.barData.barWidth)

        buffer.feed(dataSet)

        trans.pointValuesToPixel(buffer.buffer)

        val isSingleColor = dataSet.colors.size == 1

        if (isSingleColor) {
            mRenderPaint.color = dataSet.color
        }

        var 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.color = dataSet.getColor(j / 4)}// c.rawrect (// previous source code
// buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
// buffer.buffer[j + 3], mRenderPaint
/ /)
            val rectF = RectF(
                buffer.buffer[j],
                buffer.buffer[j + 1], buffer.buffer[j + 2], buffer.buffer[j + 3]
            )
            val path = Path()
            path.addRoundRect(
                rectF,
                floatArrayOf(14f.14f.14f.14f.14f.0f.0f.0f),
                Path.Direction.CCW
            )
            c.drawPath(path, mRenderPaint)
            if (drawBorder) {
                c.drawPath(path, mRenderPaint)
            }
            j += 4}}}Copy the code
C. rawRect()// Previous source code
buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint) uses the Canvas drawRect method to draw the rectangle, So I want to change the drawing method to draw a rectangle with rounded corners so I changed it to val rectF = rectF (buffer.buffer[j],buffer.buffer[j +1],buffer.buffer[j + 2], buffer.buffer[j + 3])
val path = Path()
path.addRoundRect(rectF,floatArrayOf(14f.14f.14f.14f.14f.0f.0f.0f), Path, Direction CCW) then. I called the path method which is used to draw geometric shapes and drew rounded rectangles hahaCopy the code

And then what. You define a class, CustomBarChart, to pass values

import android.content.Context
import android.util.AttributeSet
import com.github.mikephil.charting.charts.BarChart


class CustomBarChart : BarChart {
    constructor(context: Context?) : super(context) {} constructor(context: Context? , attrs: AttributeSet?) :super(context, attrs) {} constructor(context: Context? , attrs: AttributeSet? , defStyle: Int) :super(context,
        attrs,
        defStyle) {
    }

    override fun init(a) {
        super.init()
        mRenderer = SuddleBarChartRenderer(this, mAnimator, mViewPortHandler)
    }
}
Copy the code

After passing the value, bind the rewritten source code to your XML structure as follows

<com.example. Your path. CustomBarChart android:id="@+id/chart"
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:background="@color/white"
            android:padding="3dp" />
Copy the code

After clicking on the bar chart, there are two kinds of boxes, one is to modify the rounded corner, and the other is to add the rectangle after clicking, which does not work. Later I found a way, and found that in the source code, The drawhigh lights method in BarChartRenderer is used to setup the lighted rectangle selected by clicking on the bar graph

Add the following code to the SuddleBarChartRenderer class

override fun drawHighlighted(c: Canvas, indices: Array<Highlight>) {
        val barData = mChart.barData
        for (high in indices) {
            val set = barData.getDataSetByIndex(high.dataSetIndex)
            if (set == null| |! set.isHighlightEnabled)continue
            val e = set.getEntryForXValue(high.x, high.y)
            if(! isInBoundsX(e, set))continueval trans = mChart.getTransformer(set.axisDependency) mHighlightPaint.color = set.highLightColor mHighlightPaint.alpha =  set.highLightAlpha val isStack =if (high.stackIndex >= 0 && e.isStacked) true else false
            val y1: Float
            val y2: Float
            if (isStack) {
                if (mChart.isHighlightFullBarEnabled) {
                    y1 = e.positiveSum
                    y2 = -e.negativeSum
                } else {
                    val range = e.ranges[high.stackIndex]
                    y1 = range.from
                    y2 = range.to
                }
            } else {
                y1 = e.y
                y2 = 0f
            }
            prepareBarHighlight(e.x, y1, y2, barData.barWidth / 2f, trans)
            setHighlightDrawPos(high, mBarRect)
            val path = Path()
// path.addRoundRect(
// mBarRect,
// floatArrayOf(30f, 30f, 30f, 30f, 30f, 0f, 0f, 0f),
// Path.Direction.CCW
/ /)
            c.drawRoundRect(mBarRect,25.toFloat(),25.toFloat(),mHighlightPaint)
// c.paint (mBarRect, mHighlightPaint}}Copy the code

So load it up and you’re done.