如何修改MPAndroidChart中柱状图的柱子样式?(圆角/自定义Drawable)
MPAndroidChart柱状图样式修改方案
针对你的需求,既可以实现柱子的圆角处理,也可以设置自定义Drawable来定制柱子样式,以下是具体实现方式:
一、仅实现柱子圆角处理(推荐,适配目标样式)
1. 全局圆角(四个角均圆角)
如果不需要区分顶部/底部圆角,MPAndroidChart 3.0+版本可以直接通过BarDataSet的barBorderRadius属性快速设置:
val dataSet = BarDataSet(entries, "") // 设置圆角半径,数值根据需求调整 dataSet.barBorderRadius = 8f
2. 仅顶部圆角(匹配目标样式)
如果需要仅顶部圆角,需要自定义柱子渲染器,替换默认的BarChartRenderer:
class RoundTopBarChartRenderer(chart: BarChart, animator: ChartAnimator, viewPortHandler: ViewPortHandler) : BarChartRenderer(chart, animator, viewPortHandler) { private val topRadius = 8f // 自定义顶部圆角半径 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 val barBuffers = mBarBuffers barBuffers[index].setPhases(phaseX, phaseY) barBuffers[index].feed(dataSet) trans.pointValuesToPixel(barBuffers[index].buffer) val isSingleColor = dataSet.colors.size == 1 if (isSingleColor) { mRenderPaint.color = dataSet.color } var j = 0 while (j < barBuffers[index].buffer.size step 4) { if (!mViewPortHandler.isInBoundsLeft(barBuffers[index].buffer[j + 2])) { j += 4 continue } if (!mViewPortHandler.isInBoundsRight(barBuffers[index].buffer[j])) { break } if (!isSingleColor) { mRenderPaint.color = dataSet.getColor(j / 4) } // 绘制仅顶部圆角的柱子 val left = barBuffers[index].buffer[j] val top = barBuffers[index].buffer[j + 1] val right = barBuffers[index].buffer[j + 2] val bottom = barBuffers[index].buffer[j + 3] val path = Path() // 顶部左圆角 path.moveTo(left, bottom) path.lineTo(left, top + topRadius) path.arcTo(RectF(left, top, left + topRadius * 2, top + topRadius * 2), 180f, 90f) // 顶部右圆角 path.lineTo(right - topRadius, top) path.arcTo(RectF(right - topRadius * 2, top, right, top + topRadius * 2), 270f, 90f) path.lineTo(right, bottom) path.close() c.drawPath(path, mRenderPaint) if (drawBorder) { c.drawPath(path, mBarBorderPaint) } j += 4 } } }
然后在你的barChart函数中,初始化chart后替换渲染器:
// 替换为自定义顶部圆角渲染器 chart.renderer = RoundTopBarChartRenderer(chart, chart.animator, chart.viewPortHandler)
二、设置自定义柱子Drawable
如果需要更复杂的柱子样式(比如渐变、纹理填充等),可以通过两种方式实现:
1. 单个柱子设置图标
给指定BarEntry绑定自定义Drawable:
// 创建BarEntry时设置图标 val entry = BarEntry(xValue, yValue, ContextCompat.getDrawable(activity, R.drawable.custom_bar_drawable)) // 开启图标绘制 dataSet.setDrawIcons(true) // 调整图标位置(按需修改) dataSet.iconOffset = MPPointF(0f, -20f)
2. 全局自定义Drawable渲染
如果需要所有柱子使用同一个自定义Drawable,修改自定义渲染器的drawDataSet方法,用drawable.draw(canvas)替代原有的矩形绘制逻辑即可。
修改后的完整示例代码
fun barChart( activity: Activity, chart: BarChart, entries: ArrayList<BarEntry>, columnsNames: ArrayList<String>, colors: ArrayList<Int>, ) { // 替换为自定义顶部圆角渲染器 chart.renderer = RoundTopBarChartRenderer(chart, chart.animator, chart.viewPortHandler) val colorsTemplate = intArrayOf( Color.rgb(74, 160, 150), Color.rgb(74, 160, 150), Color.rgb(74, 160, 150), Color.rgb(74, 160, 150), Color.rgb(74, 160, 150) ) val colorList: ArrayList<Int> = ArrayList() for (color in colorsTemplate) { colorList.add(color) } val dataSet = BarDataSet(entries, "") val decimalFormat = DecimalFormat("0.##") dataSet.setValueFormatter(object : ValueFormatter() { override fun getFormattedValue(value: Float): String { return decimalFormat.format(value) } }) dataSet.colors = colorList val data = BarData(dataSet) data.barWidth = 0.5f data.setDrawValues(true) chart.setData(data) chart.setAutoScaleMinMaxEnabled(true) val xAxis = chart.xAxis xAxis.valueFormatter = IndexAxisValueFormatter(columnsNames) xAxis.position = XAxis.XAxisPosition.BOTTOM xAxis.setDrawGridLines(false) xAxis.setDrawAxisLine(false) xAxis.granularity = 1f xAxis.labelCount = columnsNames.size xAxis.labelRotationAngle = 0f // 360f等同于不旋转,改为0f更直观 chart.legend.isEnabled = false chart.description.isEnabled = false chart.axisRight.isEnabled = false chart.axisLeft.labelCount = 3 chart.axisLeft.axisMinimum = 0f chart.animateY(1000) chart.invalidate() } // 自定义顶部圆角柱子渲染器 class RoundTopBarChartRenderer(chart: BarChart, animator: ChartAnimator, viewPortHandler: ViewPortHandler) : BarChartRenderer(chart, animator, viewPortHandler) { private val topRadius = 8f // 自定义顶部圆角半径 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 val barBuffers = mBarBuffers barBuffers[index].setPhases(phaseX, phaseY) barBuffers[index].feed(dataSet) trans.pointValuesToPixel(barBuffers[index].buffer) val isSingleColor = dataSet.colors.size == 1 if (isSingleColor) { mRenderPaint.color = dataSet.color } var j = 0 while (j < barBuffers[index].buffer.size step 4) { if (!mViewPortHandler.isInBoundsLeft(barBuffers[index].buffer[j + 2])) { j += 4 continue } if (!mViewPortHandler.isInBoundsRight(barBuffers[index].buffer[j])) { break } if (!isSingleColor) { mRenderPaint.color = dataSet.getColor(j / 4) } // 绘制仅顶部圆角的柱子 val left = barBuffers[index].buffer[j] val top = barBuffers[index].buffer[j + 1] val right = barBuffers[index].buffer[j + 2] val bottom = barBuffers[index].buffer[j + 3] val path = Path() // 顶部左圆角 path.moveTo(left, bottom) path.lineTo(left, top + topRadius) path.arcTo(RectF(left, top, left + topRadius * 2, top + topRadius * 2), 180f, 90f) // 顶部右圆角 path.lineTo(right - topRadius, top) path.arcTo(RectF(right - topRadius * 2, top, right, top + topRadius * 2), 270f, 90f) path.lineTo(right, bottom) path.close() c.drawPath(path, mRenderPaint) if (drawBorder) { c.drawPath(path, mBarBorderPaint) } j += 4 } } }
内容的提问来源于stack exchange,提问作者pyroblinchik
相关产品推荐
相关产品推荐

