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

如何在Kotlin中使用MPAndroidChart为堆叠柱状图添加带详情的标记视图

How to Implement Custom Marker View for Stacked BarChart in MPAndroidChart

Hey there! I see you're trying to add a custom marker view to your stacked BarChart using MPAndroidChart, and you're stuck on getting it to show the right details when tapping a bar. Let's walk through the steps to fix this properly.

Step 1: Create a Proper CustomMarkerView Class

The issue with your current setup is that you're passing a temporary hoursValuesArray (which gets cleared in your loop) to the MarkerView—this won't hold the actual data for all your bars. Instead, we need a MarkerView that can pull the relevant data directly from the tapped BarEntry.

Here's a complete implementation of your CustomMarkerView:

class CustomMarkerView(
    context: Context,
    layoutResource: Int,
    private val stackLabels: Array<String> // Pass your stack labels here (the 3 time periods)
) : MarkerView(context, layoutResource) {

    // Reference the views in your custom_marker_view_layout
    private val tvTimePeriod1: TextView = findViewById(R.id.tv_time_period_1)
    private val tvValue1: TextView = findViewById(R.id.tv_value_1)
    private val tvTimePeriod2: TextView = findViewById(R.id.tv_time_period_2)
    private val tvValue2: TextView = findViewById(R.id.tv_value_2)
    private val tvTimePeriod3: TextView = findViewById(R.id.tv_time_period_3)
    private val tvValue3: TextView = findViewById(R.id.tv_value_3)

    override fun refreshContent(e: Entry?, highlight: Highlight?) {
        super.refreshContent(e, highlight)
        
        // Cast the Entry to BarEntry since we're dealing with a BarChart
        val barEntry = e as BarEntry
        
        // Get the stacked values from the BarEntry
        val stackedValues = barEntry.yVals ?: return
        
        // Update each text view with the corresponding stack label and value
        if (stackedValues.size >= 1) {
            tvTimePeriod1.text = stackLabels[0]
            tvValue1.text = stackedValues[0].toString() // Format this as needed
        }
        if (stackedValues.size >= 2) {
            tvTimePeriod2.text = stackLabels[1]
            tvValue2.text = stackedValues[1].toString()
        }
        if (stackedValues.size >= 3) {
            tvTimePeriod3.text = stackLabels[2]
            tvValue3.text = stackedValues[2].toString()
        }
    }

    // Optional: Adjust the marker's position relative to the tap point
    override fun getOffset(): MPPointF {
        // Move the marker up by half its height so it sits above the tap
        return MPPointF(-(width / 2).toFloat(), -height.toFloat())
    }
}

Make sure your custom_marker_view_layout.xml has three pairs of TextViews (one for each stack segment) to display the time period and its corresponding value.

Step 2: Fix Your Marker Initialization in the Main Code

In your original code, you were passing hoursValuesArray (which is empty after the loop) to the MarkerView. Instead, pass the stackLabels array you defined, so the MarkerView knows the time periods for each stack segment.

Update this part of your code:

// Replace your old MarkerView initialization with this
val stackLabelsArray = arrayOf("00:00 - 06:00 h", "06:00 - 18:00 h", "18:00 - 24:00 h")
val markerView = CustomMarkerView(requireContext(), R.layout.custom_marker_view_layout, stackLabelsArray )

// Keep the rest of your BarDataSet setup
val barDataSet = BarDataSet(entriesVerticalBar, "")
barDataSet.colors = verticalBarChartColors
barDataSet.valueTextSize = 8f
barDataSet.stackLabels = stackLabelsArray // Reuse the same array here
barDataSet.valueTextColor = resources.getColor(R.color.white)

// Don't forget to enable touch interactions for the chart
val barChart: BarChart = bar_chart_details
barChart.setTouchEnabled(true)
barChart.isHighlightPerTapEnabled = true // Ensure tapping highlights the bar and shows marker
barChart.marker = markerView

// Set the rest of your BarData as before
val barData = BarData(barDataSet)
barData.setValueFormatter(VerticalBarChart.DecimalRemover(DecimalFormat("###")))
barChart.data = barData
barChart.invalidate() // Refresh the chart to apply changes

Step 3: Key Notes to Remember

  • Access Stacked Values: Use barEntry.yVals to get the individual values for each stack segment of the tapped bar. This array will have exactly 3 elements since you're adding three values per BarEntry.
  • Formatting Values: If you need to format the values (like converting floats to hours/minutes), adjust the toString() calls in the MarkerView to use your transformDataForChart function or a custom formatter.
  • Layout Adjustments: If the marker doesn't position correctly, tweak the getOffset() method to move it where you want relative to the tap point.

That should do it! Now when you tap any bar in your stacked BarChart, the custom marker will pop up showing the details for each of the three time periods.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:17:50