夜阑卧听风吹雨

铁马冰河入梦来

Loading

MPAndroidChart setLabelRotationAngle bug

MPAndroidChart setLabelRotationAngle bug(应该包括其他关于修改x/y label的bug)

库是好库,但就是不更新了。。

bug 描述:修改 labelRotationAnglesetLabelRotationAngle()),手势缩放一下视图,才触发自动调整视图,会导致图表大小发生变化。用起来就是,第一次显示,label被截断,必须手动缩放一下图表,才能触发视图自适应。

解决过程

上 github 搜一下,也是一个已知陈年老 bug:https://github.com/PhilJay/MPAndroidChart/issues/3298#issuecomment-442241286

谷歌翻译:我尝试旋转标签 xAxis.setLabelRotationAngle(-30f); 这有帮助,但对于第一次渲染它被裁剪,我必须缩放图表以重新渲染,然后显示完整的标签。不知道如何强制初始重新渲染。

继续 github 上看了一个 pr,感觉改的也不好。google 了一圈,没有找到一个很好的不改动库源代码解决方法。

于是自己摸索了下:全文无图(懒

先知道一下某几个方法的意义(基于折线统计图):

mXAxisRenderer.computeAxis():涉及计算 xLabel 的宽高:mXAxis.mLabelRotatedHeightmXAxis.mLabelRotatedWidth

BarLineChartBase.calculateOffsets():涉及计算图表的宽高信息等 ViewPortHandler.mContentRect

调试了下,得到原先大致逻辑:

  1. setDate(),则 notifyDataSetChanged(),触发一次计算 mXAxisRenderer.computeAxis()calculateOffsets()
  2. onDraw 又触发一次 calculateOffsets()mXAxisRenderer.computeAxis() 直接绘制出 x、y 轴,以及上面的 label 标签;
  3. 然后是绘制图上的点,省略。

总结原因:当我们设置 data 的时候,会立即直接计算出对应的 label 宽高信息,而后续我们再设置 xAxis 等轴信息的时候就无法参与计算。导致最后绘图异常。

放大触发原因

手动放大 onTouch 会触发 mChart.calculateOffsets(),该方法会更新 ViewPortHandler.mContentRect 更新 bottom,随后再触发 onDraw

点击不触发原因

点击触发 BarLineChartBase.onDraw -> mXAxisRenderer.computeAxis 更新计算 mXAxis.mLabelRotatedHeightmXAxis.mLabelRotatedWidth;(加上bottom)
并画标签:mXAxisRenderer.renderAxisLabels(canvas);

好像没有重新计算 bottom 重绘啊,忘记了,笔者写此文时也没有验证,以上摘自草稿记录

解决方案

既然知道大致逻辑,那就很好办了。

我们直接先设置好轴信息,再 setDate() 即可!!!

本来是只想先把 setLabelRotationAngle()(即 lineChart.xAxis.labelRotationAngle),放在 setData() 前面。

测试发现高度最终会有些许出入,表现出来也就是旋转后的 label 会有部分被切掉,也就是展示高度虽有变高,但仍不够。

一想,我们对轴做了那么多自定义,那么这个误差也是理所当然的。

// kotlin举例
fun constructChart(analyzedData: AnalyzedData) {
    lineChart.tag = analyzedData
    lineChart.description.text = "数据图表"
    lineChart.description.yOffset = 22f
    lineChart.description.textColor = colorBoarder
    lineChart.setNoDataText("暂无数据")
    lineChart.setNoDataTextColor(primaryColor)

    val xCount = 999f

    // 设置 X 轴
    val xAxis = lineChart.xAxis
    xAxis.axisMaximum = xCount
    xAxis.axisMinimum = 0f
    xAxis.position = XAxis.XAxisPosition.BOTTOM
    xAxis.setDrawAxisLine(false)
    xAxis.setDrawGridLines(false)
    // 设置数量
    xAxis.setLabelCount(xCount.toInt())
    xAxis.valueFormatter = analyzedData
    xAxis.textColor = colorBoarder
    xAxis.isGranularityEnabled = true
    xAxis.setGranularity(1f)
    lineChart.xAxis.labelRotationAngle = when {
        xCount > 25f -> -90f
        xCount > 13f -> -45f
        else -> 0f
    }

    // 设置 Y 轴
    val yRightAxis = lineChart.axisRight
    yRightAxis.axisMaximum = analyzedData.ceilMaxY
    yRightAxis.axisMinimum = 0f
    LogUtils.log("YAxisMaximum: ${yRightAxis.axisMaximum}")
    yRightAxis.setDrawGridLines(true)
    yRightAxis.enableGridDashedLine(15f, 5f, 0f)
    yRightAxis.textColor = colorBoarder
    yRightAxis.isGranularityEnabled = true
    yRightAxis.setGranularity(1f)

    val yLeftAxis = lineChart.axisLeft
    yLeftAxis.axisMaximum = analyzedData.ceilMaxY
    yLeftAxis.axisMinimum = 0f
    yLeftAxis.setDrawLabels(false)
    yLeftAxis.setDrawGridLines(false)
    lineChart.animateXY(600, 600, Easing.EaseInSine, Easing.EaseInSine)

    // 设置图例
    val legend: Legend = lineChart.legend
    legend.isEnabled = false

    // 最后设置数据,第一次设置时也会触发notifyDataSetChanged,重新计算
    lineChart.data = analyzedData.lineData
}

最后,此外如果自动计算并没有全部显示 label,可以尝试设置额外 offset

lineChart.setExtraOffsets(10f, 80f, 10f, if (xCount > 25) 10f else 0f)

写文章的时候,没有再调试了,全凭草稿写的,图都懒得弄。仅做一个记录。可能有所纰漏,欢迎指出。
或许可以尝试:https://github.com/AppDevNext/AndroidChart

posted @ 2024-04-06 17:17  二次蓝  阅读(41)  评论(0编辑  收藏  举报