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

如何在MPAndroidChart的组合图表及带堆叠图表的组合图表中设置多行XAxis值?XAxisRenderer失效问题解决

Hey there! Let's work through your MPAndroidChart questions step by step—both are focused on adding multi-line X-axis labels to combined charts, with an extra challenge when stacked charts are involved and fixing broken XAxisRenderer behavior.

1. Multi-line X-axis in a Regular Combined Chart

By default, MPAndroidChart's XAxis doesn't support multi-line labels out of the box, but you can easily add this functionality with a custom XAxisRenderer. Here's what to do:

  • Step 1: Prepare your X-axis labels with line breaks
    First, define your X-axis labels as strings containing \n where you want the line split. For example:

    val xLabels = listOf(
        "Q1\n2024",
        "Q2\n2024",
        "Q3\n2024",
        "Q4\n2024"
    )
    
  • Step 2: Create a custom XAxisRenderer
    Extend the default XAxisRenderer and override the drawLabels() method to handle multi-line text. The key is to split each label by \n and draw each line separately, adjusting the Y position for each line:

    class MultiLineXAxisRenderer(
        viewPortHandler: ViewPortHandler,
        xAxis: XAxis,
        trans: Transformer
    ) : XAxisRenderer(viewPortHandler, xAxis, trans) {
    
        override fun drawLabels(c: Canvas, posX: Float, anchor: PointF) {
            val labelRotationDegrees = mXAxis.labelRotationAngle
            val labels = mXAxis.labels
    
            if (labels.isEmpty()) return
    
            val paint = mAxisLabelPaint
            paint.color = mXAxis.textColor
            paint.textSize = mXAxis.textSize
    
            val labelHeight = paint.fontMetricsInt.descent - paint.fontMetricsInt.ascent
            val lineSpacing = labelHeight * 0.2f // Adjust spacing between lines as needed
    
            for (i in labels.indices) {
                val label = labels[i]
                val lines = label.split("\n")
                var yOffset = posX // Start at the original Y position
    
                for (line in lines) {
                    val x = mViewPortHandler.contentLeft() + mXAxis.mLabelWidth * i + mXAxis.xOffset
                    if (labelRotationDegrees != 0f) {
                        c.save()
                        c.translate(x, yOffset)
                        c.rotate(-labelRotationDegrees)
                        c.drawText(line, 0f, anchor.y, paint)
                        c.restore()
                    } else {
                        c.drawText(line, x, yOffset, paint)
                    }
                    yOffset += labelHeight + lineSpacing // Move down for the next line
                }
            }
        }
    }
    
  • Step 3: Attach the custom renderer to your CombinedChart
    After setting up your chart, replace the default renderer with your custom one:

    val combinedChart = findViewById<CombinedChart>(R.id.combinedChart)
    combinedChart.xAxis.apply {
        valueFormatter = object : ValueFormatter() {
            override fun getFormattedValue(value: Float): String {
                return xLabels.getOrElse(value.toInt()) { "" }
            }
        }
        position = XAxis.XAxisPosition.BOTTOM
        setDrawLabels(true)
    }
    
    // Set custom renderer
    combinedChart.xAxisRenderer = MultiLineXAxisRenderer(
        combinedChart.viewPortHandler,
        combinedChart.xAxis,
        combinedChart.getTransformer(YAxis.AxisDependency.LEFT)
    )
    

2. Multi-line X-axis in Combined Chart with Stacked Charts + Fixing XAxisRenderer Issues

When stacked charts are part of your combined chart, the default XAxisRenderer can misalign labels or fail to render properly because it doesn't account for the stacked series' layout. Here's how to fix this:

Key Fixes for XAxisRenderer with Stacked Charts

  1. Adjust label positioning logic
    In your custom MultiLineXAxisRenderer, make sure the X position calculation accounts for the chart's full width and the number of entries, not just the left transformer. Stacked charts can shift the viewport, so using the chart's content width ensures labels stay aligned.

  2. Ensure the renderer is bound to the correct transformer
    For combined charts with multiple axis dependencies, use the transformer that matches your primary axis (usually LEFT) but verify that it's correctly updating the viewport.

Updated Custom Renderer for Stacked Charts

Modify the drawLabels() method to handle stacked chart alignment:

class StackedMultiLineXAxisRenderer(
    viewPortHandler: ViewPortHandler,
    xAxis: XAxis,
    trans: Transformer
) : XAxisRenderer(viewPortHandler, xAxis, trans) {

    override fun drawLabels(c: Canvas, posX: Float, anchor: PointF) {
        val labelRotationDegrees = mXAxis.labelRotationAngle
        val labels = mXAxis.labels
        if (labels.isEmpty()) return

        val paint = mAxisLabelPaint
        paint.color = mXAxis.textColor
        paint.textSize = mXAxis.textSize

        val labelHeight = paint.fontMetricsInt.descent - paint.fontMetricsInt.ascent
        val lineSpacing = labelHeight * 0.2f
        val entryCount = labels.size
        val contentWidth = mViewPortHandler.contentWidth()
        val labelWidth = contentWidth / entryCount // Split width evenly for each label

        for (i in labels.indices) {
            val label = labels[i]
            val lines = label.split("\n")
            var yOffset = posX

            // Calculate X position centered on each entry (critical for stacked charts)
            val x = mViewPortHandler.contentLeft() + labelWidth * i + labelWidth / 2f - paint.measureText(lines.first()) / 2f + mXAxis.xOffset

            for (line in lines) {
                if (labelRotationDegrees != 0f) {
                    c.save()
                    c.translate(x, yOffset)
                    c.rotate(-labelRotationDegrees)
                    c.drawText(line, 0f, anchor.y, paint)
                    c.restore()
                } else {
                    c.drawText(line, x - paint.measureText(line)/2f, yOffset, paint)
                }
                yOffset += labelHeight + lineSpacing
            }
        }
    }
}

Attach the Updated Renderer

Make sure to set this renderer after configuring your stacked series:

// After adding stacked bar data to your combined chart
combinedChart.xAxisRenderer = StackedMultiLineXAxisRenderer(
    combinedChart.viewPortHandler,
    combinedChart.xAxis,
    combinedChart.getTransformer(YAxis.AxisDependency.LEFT)
)

Additional Troubleshooting for Renderer Issues

  • Check if the renderer is being applied
    Sometimes, combined charts override renderers when you add new data. Always set the custom renderer after adding all your chart data sets.
  • Verify label visibility
    Ensure xAxis.setDrawLabels(true) is called, and that the X-axis position (e.g., BOTTOM) has enough space to draw multi-line labels. Adjust xAxis.yOffset to add padding if labels are cut off.
  • Test with a minimal example
    If the renderer still isn't working, strip down your chart setup to just the stacked series and multi-line X-axis to isolate any conflicts with other chart configurations.

内容的提问来源于stack exchange,提问作者Shafiq ur Rehman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:37:31