You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MpAndroidChart横向柱状图正负柱子圆角实现问题求助

解决MPAndroidChart横向柱状图正负柱子圆角问题

你的现有实现主要问题在于没有针对正负柱子分别处理圆角位置,且采用「先画矩形再用CLEAR模式擦出圆角」的方式不仅容易出现绘制异常(比如图层混合问题),还无法实现单根柱子的独立圆角效果。下面是修正后的完整实现方案:

核心思路

  1. 对每个柱子单独绘制,根据数值正负判断圆角方向:
    • 正值柱子:仅右侧(靠近X轴正方向)设置圆角
    • 负值柱子:仅左侧(靠近X轴负方向)设置圆角
    • (可根据需求调整为两端都圆角)
  2. 使用Path构建带圆角的矩形路径,替代原有的画矩形+擦除方案,避免图层混合问题
  3. 正确结合动画的phaseX/phaseY参数,保证动画过程中圆角效果正常

修正后的自定义Renderer代码

package com.almaraiquest.Utils
import android.graphics.*
import com.github.mikephil.charting.animation.ChartAnimator
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet
import com.github.mikephil.charting.renderer.HorizontalBarChartRenderer
import com.github.mikephil.charting.utils.ViewPortHandler

class MyCustomChartRender(
    chart: BarDataProvider,
    animator: ChartAnimator,
    viewPortHandler: ViewPortHandler
) : HorizontalBarChartRenderer(chart, animator, viewPortHandler) {

    private val cornerRadius = 30f // 自定义圆角大小
    private val path = Path()
    private val rectF = RectF()

    override fun drawDataSet(c: Canvas?, dataSet: IBarDataSet?, index: Int) {
        if (c == null || dataSet == null) return
        
        val trans = mChart.getTransformer(dataSet.axisDependency)
        val phaseX = mAnimator.phaseX
        val phaseY = mAnimator.phaseY

        val buffer = mBarBuffers[index]
        buffer.setPhases(phaseX, phaseY)
        buffer.setDataSet(index)
        buffer.setInverted(mChart.isInverted(dataSet.axisDependency))
        buffer.feed(dataSet)

        trans.pointValuesToPixel(buffer.buffer)

        var j = 0
        while (j < buffer.size()) {
            if (!mViewPortHandler.isInBoundsTop(buffer.buffer[j + 3])) break
            if (!mViewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) {
                j += 4
                continue
            }

            // 获取当前柱子的四个边界坐标
            val left = buffer.buffer[j]
            val top = buffer.buffer[j + 1] + 10f // 上下边距,和你原来的设置一致
            val right = buffer.buffer[j + 2]
            val bottom = buffer.buffer[j + 3] - 10f

            // 获取当前柱子的数值,判断正负
            val entry = dataSet.getEntryForIndex(j / 4)
            val value = entry.y

            // 构建带圆角的路径
            path.reset()
            rectF.set(left, top, right, bottom)
            
            when {
                value > 0 -> {
                    // 正值柱子:右侧圆角
                    path.addRoundRect(
                        rectF,
                        floatArrayOf(0f, 0f, cornerRadius, cornerRadius, cornerRadius, cornerRadius, 0f, 0f),
                        Path.Direction.CW
                    )
                }
                value < 0 -> {
                    // 负值柱子:左侧圆角
                    path.addRoundRect(
                        rectF,
                        floatArrayOf(cornerRadius, cornerRadius, 0f, 0f, 0f, 0f, cornerRadius, cornerRadius),
                        Path.Direction.CW
                    )
                }
                else -> {
                    // 零值柱子:无圆角或全圆角,按需调整
                    path.addRect(rectF, Path.Direction.CW)
                }
            }

            // 设置柱子颜色并绘制路径
            mRenderPaint.color = dataSet.getColor(j / 4)
            c.drawPath(path, mRenderPaint)

            j += 4
        }
    }
}

关键细节说明

  1. 圆角方向控制:通过floatArrayOf指定四个角的圆角半径,顺序为「左上、右上、右下、左下」,针对正负值分别设置对应角的半径
  2. 边界处理:保留了你原来的上下边距(+10f/-10f),如果不需要可以移除
  3. 动画兼容:依然使用原buffer的phaseX/phaseY参数,保证柱状图动画过程中圆角效果同步
  4. 避免Xfermode问题:直接用Path绘制带圆角的形状,不需要依赖图层混合,绘制更稳定

配合你的配置代码使用

你的setHorizontalChart方法不需要修改,只需要确保设置自定义Renderer的代码正确即可:

val myCustomChartRender = MyCustomChartRender(horizonatal_chart, horizonatal_chart.animator, horizonatal_chart.viewPortHandler)
horizonatal_chart.renderer = myCustomChartRender

如果需要调整圆角大小,直接修改cornerRadius变量的值即可。

内容的提问来源于stack exchange,提问作者sak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:17:49