Android Kotlin 中使用 MPAndroidChart 绘制优雅的曲线图:封装与优化实践

发布于:2025-03-28 ⋅ 阅读:(27) ⋅ 点赞:(0)

在 Android 开发中,数据可视化是一个非常重要的功能,尤其是曲线图的绘制。MPAndroidChart 是一个功能强大的开源图表库,支持多种图表类型,但在实际使用中,直接调用其 API 可能会导致代码冗余和可维护性差的问题。

为了解决这些问题,我们可以将 MPAndroidChart 的核心功能封装成一个工具类,提供简洁易用的接口,同时支持高度自定义配置。本文将详细介绍如何封装和优化 LineChartUtil 工具类,并提供完整的使用示例。


1. 添加依赖

首先,在项目的 build.gradle 文件中添加 MPAndroidChart 的依赖:

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}

2. 封装工具类

以下是优化后的 LineChartUtil 工具类,支持高度自定义配置和动态数据更新。

LineChartUtil.kt
import android.graphics.Color
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet

object LineChartUtil {

    /**
     * 初始化 LineChart 的基本配置
     *
     * @param lineChart 目标 LineChart
     * @param isGridEnabled 是否启用网格线
     * @param isLegendEnabled 是否启用图例
     * @param isDescriptionEnabled 是否启用描述
     * @param xAxisPosition X 轴位置
     * @param yAxisMin Y 轴最小值
     * @param yAxisMax Y 轴最大值
     * @param textColor 文字颜色
     * @param gridColor 网格线颜色
     */
    fun setupLineChart(
        lineChart: LineChart,
        isGridEnabled: Boolean = false,
        isLegendEnabled: Boolean = false,
        isDescriptionEnabled: Boolean = false,
        xAxisPosition: XAxis.XAxisPosition = XAxis.XAxisPosition.BOTTOM,
        yAxisMin: Float = 0f,
        yAxisMax: Float = Float.NaN, // 默认不设置最大值
        textColor: Int = Color.BLACK,
        gridColor: Int = Color.LTGRAY
    ) {
        with(lineChart) {
            // 禁用描述
            description.isEnabled = isDescriptionEnabled
            description.textColor = textColor

            // 启用触摸手势
            setTouchEnabled(true)

            // 启用拖拽和缩放
            isDragEnabled = true
            setScaleEnabled(true)
            setPinchZoom(true)

            // 设置背景颜色
            setBackgroundColor(Color.WHITE)

            // 配置 X 轴
            xAxis.run {
                position = xAxisPosition
                setDrawGridLines(isGridEnabled)
                granularity = 1f
                isGranularityEnabled = true
                textColor = textColor
                gridColor = gridColor
            }

            // 配置左侧 Y 轴
            axisLeft.run {
                setDrawGridLines(isGridEnabled)
                axisMinimum = yAxisMin
                if (!yAxisMax.isNaN()) axisMaximum = yAxisMax
                textColor = textColor
                gridColor = gridColor
            }

            // 禁用右侧 Y 轴
            axisRight.isEnabled = false

            // 配置图例
            legend.isEnabled = isLegendEnabled
            legend.textColor = textColor
        }
    }

    /**
     * 设置曲线图数据
     *
     * @param lineChart 目标 LineChart
     * @param entries 数据点列表
     * @param label 数据集的标签
     * @param lineColor 线条颜色
     * @param valueColor 数据值颜色
     * @param lineWidth 线条宽度
     * @param circleRadius 数据点圆圈半径
     * @param mode 线条模式(直线、曲线等)
     * @param enableAnimation 是否启用动画
     * @param animationDuration 动画持续时间(毫秒)
     */
    fun setLineChartData(
        lineChart: LineChart,
        entries: List<Entry>,
        label: String,
        lineColor: Int = Color.BLUE,
        valueColor: Int = Color.RED,
        lineWidth: Float = 2f,
        circleRadius: Float = 4f,
        mode: LineDataSet.Mode = LineDataSet.Mode.CUBIC_BEZIER,
        enableAnimation: Boolean = true,
        animationDuration: Int = 1000
    ) {
        val dataSet = LineDataSet(entries, label).apply {
            color = lineColor
            valueTextColor = valueColor
            setDrawCircles(true)
            setDrawValues(true)
            this.lineWidth = lineWidth
            this.circleRadius = circleRadius
            this.mode = mode
        }

        val lineData = LineData(dataSet)
        lineChart.data = lineData

        if (enableAnimation) {
            lineChart.animateX(animationDuration)
        }

        lineChart.invalidate()
    }

    /**
     * 动态添加数据点
     *
     * @param lineChart 目标 LineChart
     * @param entry 新数据点
     * @param maxEntries 最大数据点数量(超过时移除旧数据)
     */
    fun addEntry(lineChart: LineChart, entry: Entry, maxEntries: Int = 100) {
        val data = lineChart.data ?: return
        val set = data.getDataSetByIndex(0) ?: return

        set.addEntry(entry)

        if (set.entryCount > maxEntries) {
            set.removeFirst()
        }

        data.notifyDataChanged()
        lineChart.notifyDataSetChanged()
        lineChart.moveViewToX(data.entryCount.toFloat())
    }

    /**
     * 清除图表数据
     */
    fun clearChart(lineChart: LineChart) {
        lineChart.clear()
        lineChart.invalidate()
    }
}

3. 使用示例

以下是如何在 MainActivity 中使用 LineChartUtil 工具类的完整示例。

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/lineChart"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.Entry

class MainActivity : AppCompatActivity() {

    private lateinit var lineChart: LineChart

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lineChart = findViewById(R.id.lineChart)

        // 初始化图表配置
        LineChartUtil.setupLineChart(
            lineChart,
            isGridEnabled = true,
            isLegendEnabled = true,
            xAxisPosition = XAxis.XAxisPosition.BOTTOM,
            yAxisMin = 0f,
            yAxisMax = 10f,
            textColor = Color.BLACK,
            gridColor = Color.LTGRAY
        )

        // 创建数据点
        val entries = listOf(
            Entry(0f, 4f),
            Entry(1f, 8f),
            Entry(2f, 6f),
            Entry(3f, 2f),
            Entry(4f, 7f),
            Entry(5f, 5f)
        )

        // 设置图表数据
        LineChartUtil.setLineChartData(
            lineChart,
            entries,
            label = "示例曲线图",
            lineColor = Color.GREEN,
            valueColor = Color.BLACK,
            lineWidth = 3f,
            circleRadius = 5f,
            mode = LineDataSet.Mode.CUBIC_BEZIER,
            enableAnimation = true,
            animationDuration = 1500
        )

        // 动态添加数据点
        LineChartUtil.addEntry(lineChart, Entry(6f, 9f), maxEntries = 10)
    }
}

4. 功能扩展与优化建议

  • 多数据集支持:可以通过创建多个 LineDataSet 来支持多条曲线。
  • 渐变色背景:使用 LineChart.setBackgroundColorLineChart.setDrawGridBackground 实现渐变色背景。
  • 自定义标记视图:通过 MarkerView 实现数据点的自定义标记。
  • 性能优化:减少不必要的刷新操作,避免频繁调用 invalidate()

总结

通过封装 LineChartUtil 工具类,我们能够以更简洁的方式在 Android 应用中绘制曲线图,同时支持高度自定义配置和动态数据更新。希望本文的内容能为你的开发工作带来帮助!如果你有任何问题或建议,欢迎在评论区留言。


参考文档


希望这篇博客内容对你有帮助!如果有其他需求,欢迎随时提出!