如何在Kotlin中使用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.yValsto 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 yourtransformDataForChartfunction 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

