Jetpack Compose中使用MPAndroidChart

前言

仓库地址:https://github.com/PhilJay/MPAndroidChart

文档

https://www.jianshu.com/p/fc73b490edd5

安装依赖

添加仓库

settings.gradle.kts中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
pluginManagement {
repositories {
maven("https://maven.aliyun.com/repository/central")
maven("https://maven.aliyun.com/repository/public")
maven("https://maven.aliyun.com/repository/gradle-plugin")
maven("https://maven.aliyun.com/repository/apache-snapshots")
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
maven("https://jitpack.io")
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven("https://maven.aliyun.com/repository/central")
maven("https://maven.aliyun.com/repository/public")
maven("https://maven.aliyun.com/repository/gradle-plugin")
maven("https://maven.aliyun.com/repository/apache-snapshots")
google()
mavenCentral()
maven("https://jitpack.io")
}
}

主要是

1
maven("https://jitpack.io")

添加依赖

build.gradle.kts

1
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")

使用

折线图LineChart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import android.graphics.Color
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.utils.ColorTemplate
import androidx.core.graphics.toColorInt

@Composable
fun LineChartView() {
// 获取当前上下文
val context = LocalContext.current

// 使用 AndroidView 在 Compose 中嵌入原生视图
AndroidView(
// 设置视图的修饰符,使其填满父布局的宽度并固定高度为300dp
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
// 创建 LineChart 视图的工厂函数
factory = { ctx ->
// 创建 LineChart 实例,LineChart 是 MPAndroidChart 库中用于绘制折线图的核心组件
LineChart(ctx).apply {
// 设置布局参数,使其宽高都为 MATCH_PARENT
layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
// 设置背景颜色为白色
setBackgroundColor(Color.TRANSPARENT)

// 禁用描述文本
description.isEnabled = false

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

// 启用缩放和拖动
isDragEnabled = false
setScaleEnabled(false)
setPinchZoom(false)

// 配置 X 轴
xAxis.apply {
// 设置 X 轴位置在底部
position = XAxis.XAxisPosition.BOTTOM
// 设置 X 轴文本颜色为白色
textColor = Color.WHITE
// 不绘制网格线
setDrawGridLines(true)
// 绘制轴线条
setDrawAxisLine(false)
}

// 配置 Y 轴(左侧)
axisLeft.apply {
// 设置 Y 轴文本颜色为黑色
textColor = Color.WHITE
// 绘制网格线
setDrawGridLines(true)
}

// 关闭 Y 轴右侧
axisRight.isEnabled = false

// 设置数据
data = generateLineData()
}
}
)
}

fun generateLineData(): LineData {
// 创建一个可变的 Entry 列表,用于存储数据点,Entry 是 MPAndroidChart 库中的一个类,用于表示折线图上的一个数据点
val entries = mutableListOf<Entry>()

// 假设有 10 个数据点
for (i in 0..9) {
val value = (Math.random() * 100).toFloat() // 随机生成 0-100 的数据
entries.add(Entry(i.toFloat(), value))
}
/*
LineDataSet 是 MPAndroidChart 库中管理单条折线数据及样式的核心类,其对象结构可分为 数据层、样式层 和 行为层 三大部分
*/
val dataSet = LineDataSet(entries, "示例折线")
dataSet.apply {
color = "#28E7B3".toColorInt()
setCircleColor("#ffffff".toColorInt())
valueTextColor = Color.WHITE
lineWidth = 1.5f
circleRadius = 2f
setDrawValues(true)
setDrawCircles(true)
}

return LineData(dataSet)
}

柱状图BarChart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import android.graphics.Color
import android.graphics.DashPathEffect
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.graphics.toColorInt
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.components.AxisBase
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.formatter.ValueFormatter

@Composable
fun BarChartView() {
AndroidView(
// 设置视图的修饰符,使其填满父布局的宽度并固定高度为300dp
modifier = Modifier
.fillMaxSize(),
// 创建 BarChart 视图的工厂函数
factory = { ctx ->
BarChart(ctx).apply {
// 设置布局参数,使其宽高都为 MATCH_PARENT
layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
// 设置背景颜色为白色
setBackgroundColor(Color.TRANSPARENT)

// 禁用描述文本
description.isEnabled = false

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

// 启用缩放和拖动
isDragEnabled = false
setScaleEnabled(false)
setPinchZoom(false)

// 配置 X 轴
xAxis.apply {
// 设置 X 轴位置在底部
position = XAxis.XAxisPosition.BOTTOM
// 设置 X 轴文本颜色
textColor = "#999D9B".toColorInt()
textSize = 20f
// 竖向网格线
gridColor = Color.TRANSPARENT
axisLineColor = "#dddddd".toColorInt()
}

xAxis.valueFormatter = object : ValueFormatter() {
override fun getAxisLabel(value: Float, axis: AxisBase?): String {
return value.toInt().toString() + "月"
}
}

// 配置 Y 轴(左侧)
axisLeft.apply {
// 设置 Y 轴文本颜色
textColor = "#999D9B".toColorInt()
textSize = 20f
// 横向网格线
gridColor = "#dddddd".toColorInt()
setGridDashedLine(DashPathEffect(floatArrayOf(10f, 10f), 0f))
axisLineColor = Color.TRANSPARENT
axisLineWidth = 0f

}
axisLeft.isEnabled = true
// 关闭 Y 轴右侧
axisRight.isEnabled = false

axisLeft.setValueFormatter(object : ValueFormatter() {
override fun getAxisLabel(value: Float, axis: AxisBase?): String {
return value.toString()
}
});

// 图例文字颜色
legend.textColor = "#1D1D1D".toColorInt()
legend.textSize = 20f
legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER

// 设置数据
data = generateBarData()
val dataSetCount = barData.getDataSets().size
val groupSpace = 0.3f // 组间距
val barSpace = 0.3f // 组内柱间距
barData.barWidth = (1 - groupSpace) / dataSetCount - barSpace
}
}
)
}

private fun generateBarData(): BarData {
val entries = mutableListOf<BarEntry>()

// 假设有 10 个数据点
for (i in 1..12) {
val value = (Math.random() * 100).toFloat() // 随机生成 0-100 的数据
entries.add(BarEntry(i.toFloat(), value))
}
/*
BarDataSet 是 MPAndroidChart 库中管理单条折线数据及样式的核心类,其对象结构可分为 数据层、样式层 和 行为层 三大部分
*/
val dataSet = BarDataSet(entries, "用时")
dataSet.apply {
color = "#0085F7".toColorInt()
valueTextColor = "#1D1D1D".toColorInt()
valueTextSize = 20f
setDrawValues(true)
}
return BarData(dataSet)
}

值格式化

1
2
3
4
5
6
7
8
9
10
11
dataSet.apply {
color = "#0085F7".toColorInt()
valueTextColor = "#1D1D1D".toColorInt()
valueTextSize = 20f
setDrawValues(true)
valueFormatter = object : ValueFormatter() {
override fun getBarLabel(entry: BarEntry?): String {
return entry?.y?.toInt()?.toString() ?: ""
}
}
}

饼图PieChart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import android.graphics.Color
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.graphics.toColorInt
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry

@Composable
fun PieChartView() {
AndroidView(
// 设置视图的修饰符,使其填满父布局的宽度并固定高度为300dp
modifier = Modifier
.fillMaxSize(),
// 创建 PieChart 视图的工厂函数
factory = { ctx ->
PieChart(ctx).apply {
// 设置布局参数,使其宽高都为 MATCH_PARENT
layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
// 设置背景颜色为白色
setBackgroundColor(Color.TRANSPARENT)

// 禁用描述文本
description.isEnabled = false

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


// 图例文字颜色
legend.textColor = "#1D1D1D".toColorInt()
legend.textSize = 16f
legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER

// 设置数据
data = generatePieData()

}
}
)
}

private fun generatePieData(): PieData {
val entries = mutableListOf<PieEntry>()

entries.add(PieEntry(40f, "优秀"))
entries.add(PieEntry(20f, "满分"))
entries.add(PieEntry(30f, "及格"))
entries.add(PieEntry(10f, "不及格"))
/*
PieDataSet 是 MPAndroidChart 库中管理单条折线数据及样式的核心类,其对象结构可分为 数据层、样式层 和 行为层 三大部分
*/
val dataSet = PieDataSet(entries, "")
dataSet.apply {
colors = listOf(
"#0085F7".toColorInt(),
"#FE9429".toColorInt(),
"#37C427".toColorInt(),
"#FCC138".toColorInt(),
"#F24949".toColorInt(),
"#ED4A99".toColorInt(),
"#6B30FF".toColorInt(),
"#798CB5".toColorInt(),
"#5DDFF0".toColorInt(),
"#2F65FA".toColorInt(),
"#FF6D1F".toColorInt(),
)
valueTextColor = "#1D1D1D".toColorInt()
valueTextSize = 20f
setDrawValues(true)
yValuePosition = PieDataSet.ValuePosition.OUTSIDE_SLICE
//设置折线的颜色
valueLineColor = Color.BLACK;
//设置数据线距离图像内部园心的距离,以百分比来计算
valueLinePart1OffsetPercentage = 100f;
//当valuePosition在外部时,表示行前半部分的长度(即折线靠近圆的那端长度)
valueLinePart1Length = 0.5f;
///当valuePosition位于外部时,表示行后半部分的长度*(即折线靠近百分比那端的长度)
valueLinePart2Length = 0.5f;
}
return PieData(dataSet)
}

值格式化

1
2
3
4
5
data.dataSet.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return value.toInt().toString()
}
}