使用MPAndroid图表库创建一个数据可视化仪表板
用户从信息中获得洞察力的最简单方法是通过数据可视化。数据可视化最常见的工具是使用图表。
本教程将使用Kotlin和开源图表库MPAndroidChart ,创建一个简单的管理仪表板,允许用户使用三种常用的图表查看数据:饼图、条形图和线图。
该应用程序将模拟游戏公园中的野生动物数据。对于数据,我们将从一个SQLite数据库中获取。数据源并不重要,你可以使用任何数据源。它可以通过JSON、Room持久化库、简单数组、本地存储等从任何API中获取。我们将在最后实现这个目标(该布局仅配置为轻型模式)。

前提条件
- Kotlin编程语言的基本知识,以及它在开发Android应用程序中的使用。
- 在你的机器上安装Android Studio或IntellijIDEA(为Android开发而配置)。
- SQLite数据库的知识。同样,这也是不必要的,因为你可以使用任何其他的数据源。
- 一般面向对象的编程(OOP)概念。
目标
在本文结束时,读者应该熟练掌握。
- 创建一个SQLite数据库。
- 使用MPAndroid图表库将图表添加到我们的项目中。
- 使用从SQLite数据库加载的数据填充图表。
第一步:设置库
创建一个新的应用程序后,按照下面的方法修改你的Gradle文件。
- 在你的应用级
build.gradle文件中添加以下依赖关系。
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
- 最后,在项目级
build.gradle文件的repositories部分下,添加这行代码。
maven { url 'https://jitpack.io' }
注意:如果你遇到了构建错误,你也可以在
settings.gradle文件的repositories部分修改这一行。
maven { url 'https://jitpack.io' }
第二步:创建一个模型类
我们将创建一个'AnimalModel'模型类,用于组织和简化数据操作。首先,请创建一个新的kotlin文件,并赋予它相同的类名。然后,添加以下几行代码。
class AnimalModel (var animalId: Int, var animalName:String, var totNumber:Int, var avgAge: Int, var avgGrowth: Int)
它为数据库中的动物的ID、名称、总数、平均年龄和平均增长率建模。
第三步:创建一个数据库处理类
为了处理数据库逻辑,我们将创建一个'DatabaseHandler'类,它扩展了SQLiteOpenHelper 类。这个扩展类为我们提供了能够操作SQLite数据库的方法。该数据库将不是一个完整的CRUD(创建、读取、更新和删除),而只是CR(创建和读取)。我们只需要创建记录,然后获取它们来填充图表。
这个处理程序类将有一个带有常量变量的伴侣对象,用于存储数据库、表和字段名。
companion object {
private val DB_VERSION = 1
private val DB_NAME = "wildDB"
private val MAIN_TABLE = "mainTable"
private val ID_FIELD = "_id"
private val NAME_FIELD = "name"
private val NUMBER_FIELD = "tot_number"
private val AGE_FIELD = "avg_age"
private val GROWTH_FIELD = "growth_rate"
}
我们还将有两个重载的方法,onCreate() 和onUpgrade() 。
onCreate() 方法将使用标准的SQL语句创建我们的表和它的字段。数据库作为一个参数被传递。
override fun onCreate(ourDB: SQLiteDatabase?) {
//creating our table with the respective fields
val CREATE_MAIN_TABLE = ("CREATE TABLE " + MAIN_TABLE + "("
+ ID_FIELD + " INTEGER PRIMARY KEY,"
+ NAME_FIELD + " TEXT,"
+ NUMBER_FIELD + " INTEGER,"
+ AGE_FIELD + " INTEGER,"
+ GROWTH_FIELD + " INTEGER" + ")")
//executing the create table query
ourDB?.execSQL(CREATE_MAIN_TABLE)
}
当你想安全地更新数据库时,你将使用onUpgrade() 方法。然而,在我们的文章中,我们将不使用它。传入的参数是数据库名称、旧版本号和新版本号。
//function to be invoked when upgrading your database
override fun onUpgrade(ourDB: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
ourDB!!.execSQL("DROP TABLE IF EXISTS " + MAIN_TABLE)
onCreate(ourDB)
}
我们将使用一个叫做addAnimalDetails() 的函数来插入记录。首先,我们把我们的动物模型类作为参数传入,以可写模式打开数据库进行修改,然后使用ContentValues对象插入模型类中的值。
插入之后,我们关闭数据库,然后返回一个状态代码,以显示操作是否成功。
//a method to insert records
fun addAnimalDetails(animal: AnimalModel):Long{
//opening the database in a writable mode to be able to make changes in it
val ourDB = this.writableDatabase
val ourContentValues = ContentValues()
ourContentValues.put(ID_FIELD, animal.animalId)
ourContentValues.put(NAME_FIELD, animal.animalName)
ourContentValues.put(NUMBER_FIELD, animal.totNumber)
ourContentValues.put(AGE_FIELD, animal.avgAge)
ourContentValues.put(GROWTH_FIELD, animal.avgGrowth)
val success = ourDB.insert(MAIN_TABLE, null, ourContentValues)
//closse the database
ourDB.close()
return success
}
最后,我们有一个方法来读取记录。我们把它叫做retreiveAnimals() 。它返回一个包含检索到的记录的通用列表。我们运行一个选择查询,在可读模式下打开数据库来 "读取 "记录,然后创建一个游标对象来存储检索到的记录。
接下来,我们执行查询并在游标中进行迭代,同时将值分配给模型类,直到所有的记录被获取。try-catch帮助我们在执行查询时捕获任何SQLite异常。
注意:
@SuppressLint("Range")注解用于抑制出现的错误,因此需要我们为游标明确设置一个范围cursor.getInt()方法。
//method to read the animal records
@SuppressLint("Range")
fun retreiveAnimals():List<AnimalModel>{
//a list to be returned after fetching the records
val animalList:ArrayList<AnimalModel> = ArrayList<AnimalModel>()
//the SELECT query
val selectQuery = "SELECT * FROM $MAIN_TABLE"
//we open the database in a readable mode for fetching the records
val ourDB = this.readableDatabase
//cursor for storing the retrieved records
var ourCursor: Cursor? = null
try{
ourCursor = ourDB.rawQuery(selectQuery, null)
}catch (e: SQLiteException) {
ourDB.execSQL(selectQuery)
return ArrayList()
}
var animalIDReturned: Int
var animalNameReturned: String
var animalNumberReturned: Int
var animalAgeReturned:Int
var animalGrowthReturned:Int
//fetch all the records until all are finished
if (ourCursor.moveToFirst()) {
do {
//assign the values gotten to the respective strings
animalIDReturned = ourCursor.getInt(ourCursor.getColumnIndex("_id"))
animalNameReturned = ourCursor.getString(ourCursor.getColumnIndex("name"))
animalNumberReturned = ourCursor.getInt(ourCursor.getColumnIndex("tot_number"))
animalAgeReturned = ourCursor.getInt(ourCursor.getColumnIndex("avg_age"))
animalGrowthReturned = ourCursor.getInt(ourCursor.getColumnIndex("growth_rate"))
//add the values to the Model class and later to the arraylist
val animalRow= AnimalModel(animalId=animalIDReturned,animalName=animalNameReturned,totNumber=animalNumberReturned,avgAge=animalAgeReturned,avgGrowth=animalGrowthReturned)
animalList.add(animalRow)
} while (ourCursor.moveToNext())
}
return animalList
}
这就是这个类的完整代码。
import android.annotation.SuppressLint
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteException
class DatabaseHandler(context: Context): SQLiteOpenHelper(context,DB_NAME,null,DB_VERSION) {
companion object {
private val DB_VERSION = 1
private val DB_NAME = "wildDB"
private val MAIN_TABLE = "mainTable"
private val ID_FIELD = "_id"
private val NAME_FIELD = "name"
private val NUMBER_FIELD = "tot_number"
private val AGE_FIELD = "avg_age"
private val GROWTH_FIELD = "growth_rate"
}
override fun onCreate(ourDB: SQLiteDatabase?) {
//creating our table with the respective fields
val CREATE_MAIN_TABLE = ("CREATE TABLE " + MAIN_TABLE + "("
+ ID_FIELD + " INTEGER PRIMARY KEY,"
+ NAME_FIELD + " TEXT,"
+ NUMBER_FIELD + " INTEGER,"
+ AGE_FIELD + " INTEGER,"
+ GROWTH_FIELD + " INTEGER" + ")")
//executing the create table query
ourDB?.execSQL(CREATE_MAIN_TABLE)
}
//function to be invoked when upgrading your database
override fun onUpgrade(ourDB: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
ourDB!!.execSQL("DROP TABLE IF EXISTS " + MAIN_TABLE)
onCreate(ourDB)
}
//a method to insert records
fun addAnimalDetails(animal: AnimalModel):Long{
//opening the database in a writable mode to be able to make changes in it
val ourDB = this.writableDatabase
val ourContentValues = ContentValues()
ourContentValues.put(ID_FIELD, animal.animalId)
ourContentValues.put(NAME_FIELD, animal.animalName)
ourContentValues.put(NUMBER_FIELD, animal.totNumber)
ourContentValues.put(AGE_FIELD, animal.avgAge)
ourContentValues.put(GROWTH_FIELD, animal.avgGrowth)
val success = ourDB.insert(MAIN_TABLE, null, ourContentValues)
//closse the database
ourDB.close()
return success
}
//method to read the animal records
@SuppressLint("Range")
fun retreiveAnimals():List<AnimalModel>{
//a list to be returned after fetching the records
val animalList:ArrayList<AnimalModel> = ArrayList<AnimalModel>()
//the SELECT query
val selectQuery = "SELECT * FROM $MAIN_TABLE"
//we open the database in a readable mode for fetching the records
val ourDB = this.readableDatabase
//cursor for storing the retrieved records
var ourCursor: Cursor? = null
try{
ourCursor = ourDB.rawQuery(selectQuery, null)
}catch (e: SQLiteException) {
ourDB.execSQL(selectQuery)
return ArrayList()
}
var animalIDReturned: Int
var animalNameReturned: String
var animalNumberReturned: Int
var animalAgeReturned:Int
var animalGrowthReturned:Int
//fetch all the records until all are finished
if (ourCursor.moveToFirst()) {
do {
//assign the values gotten to the respective strings
animalIDReturned = ourCursor.getInt(ourCursor.getColumnIndex("_id"))
animalNameReturned = ourCursor.getString(ourCursor.getColumnIndex("name"))
animalNumberReturned = ourCursor.getInt(ourCursor.getColumnIndex("tot_number"))
animalAgeReturned = ourCursor.getInt(ourCursor.getColumnIndex("avg_age"))
animalGrowthReturned = ourCursor.getInt(ourCursor.getColumnIndex("growth_rate"))
//add the values to the Model class and later to the arraylist
val animalRow= AnimalModel(animalId=animalIDReturned,animalName=animalNameReturned,totNumber=animalNumberReturned,avgAge=animalAgeReturned,avgGrowth=animalGrowthReturned)
animalList.add(animalRow)
} while (ourCursor.moveToNext())
}
return animalList
}
}
第四步:将数据添加到数据库并填充到图表中
这一步将向我们的数据库添加记录,然后用获取的记录来填充图表。我们将通过调用我们刚刚创建的数据库处理类方法来实现这一目标。
保存记录
我们通过使用saveAnimals() 方法和使用模型类传入适当的字段来做到这一点。
//method for saving records in database
fun saveAnimals() {
val databaseHandler: DatabaseHandler = DatabaseHandler(this)
val record1 = databaseHandler.addAnimalDetails(AnimalModel(1, "Lion", 470, 7, 87))
val record2 = databaseHandler.addAnimalDetails(AnimalModel(2, "Impala", 1879, 10, 90))
val record3 = databaseHandler.addAnimalDetails(AnimalModel(3, "Leopard", 570, 13, 89))
val record4 = databaseHandler.addAnimalDetails(AnimalModel(4, "Crocodile", 150, 30, 66))
}
检索记录
我们调用DatabaseHandler 类中的retreiveAnimals() 方法来读取记录并将其存储在数组中。最后,我们通过传入数组来调用填充图表的方法。
fun retrieveRecordsAndPopulateCharts() {
//creating the instance of DatabaseHandler class
val databaseHandler: DatabaseHandler = DatabaseHandler(this)
//calling the retreiveAnimals method of DatabaseHandler class to read the records
val animal: List<AnimalModel> = databaseHandler.retreiveAnimals()
//create arrays for storing the values gotten
val animalIDArray = Array<Int>(animal.size) { 0 }
val animalNameArray = Array<String>(animal.size) { "natgeo" }
val animalNumberArray = Array<Int>(animal.size) { 0 }
val animalAgeArray = Array<Int>(animal.size) { 0 }
val animalGrowthArray = Array<Int>(animal.size) { 0 }
//add the records till done
var index = 0
for (a in animal) {
animalIDArray[index] = a.animalId
animalNameArray[index] = a.animalName
animalNumberArray[index] = a.totNumber
animalAgeArray[index] = a.avgAge
animalGrowthArray[index] = a.avgGrowth
index++
}
//call the methods for populating the charts
populatePieChart(animalNumberArray, animalNameArray)
populateBarChart(animalAgeArray)
populateLineChart(animalGrowthArray)
}
填充图表
MPAndroid的图表库非常容易使用。让我们看看如何用数据填充图表。让我们从饼图开始。
饼图的值和标签都是从传递的数组中获得的。数组将存储饼图的条目。首先,OurPieEntry ,之后用一个循环添加数值和标签,这将在MainActivity 类中完成。
//an array to store the pie slices entry
val ourPieEntry = ArrayList<PieEntry>()
var i = 0
for (entry in values) {
//converting to float
var value = values[i].toFloat()
var label = labels[i]
//adding each value to the pieentry array
ourPieEntry.add(PieEntry(value, label))
i++
}
接下来,我们再次使用一个数组为饼片添加颜色。
//assigning color to each slices
val pieShades: ArrayList<Int> = ArrayList()
pieShades.add(Color.parseColor("#0E2DEC"))
pieShades.add(Color.parseColor("#B7520E"))
pieShades.add(Color.parseColor("#5E6D4E"))
pieShades.add(Color.parseColor("#DA1F12"))
一个由库使用的用于向饼图添加数据的数据集被传递到饼片的入口值中。
//add values to the pie dataset and passing them to the constructor
val ourSet = PieDataSet(ourPieEntry, "")
val data = PieData(ourSet)
然后我们设置切片的分界线宽度,为数据集添加颜色,并将该对象设置为饼图的数据属性。
//setting the slices divider width
ourSet.sliceSpace = 1f
//populating the colors and data
ourSet.colors = pieShades
ourPieChart.data = data
下一个部分是关于操纵图表的外观。同样,图表提供了许多方法和属性,你可以探索。不幸的是,我们不能在这里穷尽所有的方法。
注意:我添加了内联评论作为指导。最后一行很关键,因为它刷新了图表。
//refreshing the chart
ourPieChart.invalidate()
下面是populatePieChart() 方法的完整代码。
private fun populatePieChart(values: Array<Int>, labels: Array<String>) {
//an array to store the pie slices entry
val ourPieEntry = ArrayList<PieEntry>()
var i = 0
for (entry in values) {
//converting to float
var value = values[i].toFloat()
var label = labels[i]
//adding each value to the pieentry array
ourPieEntry.add(PieEntry(value, label))
i++
}
//assigning color to each slices
val pieShades: ArrayList<Int> = ArrayList()
pieShades.add(Color.parseColor("#0E2DEC"))
pieShades.add(Color.parseColor("#B7520E"))
pieShades.add(Color.parseColor("#5E6D4E"))
pieShades.add(Color.parseColor("#DA1F12"))
//add values to the pie dataset and passing them to the constructor
val ourSet = PieDataSet(ourPieEntry, "")
val data = PieData(ourSet)
//setting the slices divider width
ourSet.sliceSpace = 1f
//populating the colors and data
ourSet.colors = pieShades
ourPieChart.data = data
//setting color and size of text
data.setValueTextColor(Color.WHITE)
data.setValueTextSize(10f)
//add an animation when rendering the pie chart
ourPieChart.animateY(1400, Easing.EaseInOutQuad)
//disabling center hole
ourPieChart.isDrawHoleEnabled = false
//do not show description text
ourPieChart.description.isEnabled = false
//legend enabled and its various appearance settings
ourPieChart.legend.isEnabled = true
ourPieChart.legend.orientation = Legend.LegendOrientation.HORIZONTAL
ourPieChart.legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER
ourPieChart.legend.isWordWrapEnabled = true
//dont show the text values on slices e.g Antelope, impala etc
ourPieChart.setDrawEntryLabels(false)
//refreshing the chart
ourPieChart.invalidate()
}
对于条形图和线形图,逻辑是相同的。我们传入数值,使用它们的入口数组设置它们,设置它们的属性,然后显示它们。唯一的区别是由数组传入的内容。例如,我们为饼图传递了标签和值,但我们只为另外两个饼图传递了值和位置。
下面是条形图条目的一个片段。
//adding values
val ourBarEntries: ArrayList<BarEntry> = ArrayList()
var i = 0
for (entry in values) {
var value = values[i].toFloat()
ourBarEntries.add(BarEntry(i.toFloat(), value))
i++
}
下面是这两种方法的代码。
private fun populateBarChart(values: Array<Int>) {
//adding values
val ourBarEntries: ArrayList<BarEntry> = ArrayList()
var i = 0
for (entry in values) {
var value = values[i].toFloat()
ourBarEntries.add(BarEntry(i.toFloat(), value))
i++
}
val barDataSet = BarDataSet(ourBarEntries, "")
//set a template coloring
barDataSet.setColors(*ColorTemplate.COLORFUL_COLORS)
val data = BarData(barDataSet)
ourBarChart.data = data
//setting the x-axis
val xAxis: XAxis = ourBarChart.xAxis
//calling methods to hide x-axis gridlines
ourBarChart.axisLeft.setDrawGridLines(false)
xAxis.setDrawGridLines(false)
xAxis.setDrawAxisLine(false)
//remove legend
ourBarChart.legend.isEnabled = false
//remove description label
ourBarChart.description.isEnabled = false
//add animation
ourBarChart.animateY(3000)
//refresh the chart
ourBarChart.invalidate()
}
private fun populateLineChart(values: Array<Int>) {
val ourLineChartEntries: ArrayList<Entry> = ArrayList()
var i = 0
for (entry in values) {
var value = values[i].toFloat()
ourLineChartEntries.add(Entry(i.toFloat(), value))
i++
}
val lineDataSet = LineDataSet(ourLineChartEntries, "")
lineDataSet.setColors(*ColorTemplate.PASTEL_COLORS)
val data = LineData(lineDataSet)
ourLineChart.axisLeft.setDrawGridLines(false)
val xAxis: XAxis = ourLineChart.xAxis
xAxis.setDrawGridLines(false)
xAxis.setDrawAxisLine(false)
ourLineChart.legend.isEnabled = false
//remove description label
ourLineChart.description.isEnabled = false
//add animation
ourLineChart.animateX(1000, Easing.EaseInSine)
ourLineChart.data = data
//refresh
ourLineChart.invalidate()
}
完整的MainActivity 代码。
import android.os.Bundle
import android.graphics.Color
import android.graphics.Typeface
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.formatter.PercentFormatter
import com.github.mikephil.charting.utils.ColorTemplate
class MainActivity : AppCompatActivity() {
private lateinit var ourPieChart: PieChart
private lateinit var ourBarChart: BarChart
private lateinit var ourLineChart: LineChart
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ourPieChart = findViewById(R.id.ourPieChart)
ourBarChart = findViewById(R.id.ourBarChart)
ourLineChart = findViewById(R.id.ourLineChart)
saveAnimals()
retrieveRecordsAndPopulateCharts()
}
//method for saving records in database
fun saveAnimals() {
val databaseHandler: DatabaseHandler = DatabaseHandler(this)
val record1 = databaseHandler.addAnimalDetails(AnimalModel(1, "Lion", 470, 7, 87))
val record2 = databaseHandler.addAnimalDetails(AnimalModel(2, "Impala", 1879, 10, 90))
val record3 = databaseHandler.addAnimalDetails(AnimalModel(3, "Leopard", 570, 13, 89))
val record4 = databaseHandler.addAnimalDetails(AnimalModel(4, "Crocodile", 150, 30, 66))
}
fun retrieveRecordsAndPopulateCharts() {
//creating the instance of DatabaseHandler class
val databaseHandler: DatabaseHandler = DatabaseHandler(this)
//calling the retreiveAnimals method of DatabaseHandler class to read the records
val animal: List<AnimalModel> = databaseHandler.retreiveAnimals()
//create arrays for storing the values gotten
val animalIDArray = Array<Int>(animal.size) { 0 }
val animalNameArray = Array<String>(animal.size) { "natgeo" }
val animalNumberArray = Array<Int>(animal.size) { 0 }
val animalAgeArray = Array<Int>(animal.size) { 0 }
val animalGrowthArray = Array<Int>(animal.size) { 0 }
//add the records till done
var index = 0
for (a in animal) {
animalIDArray[index] = a.animalId
animalNameArray[index] = a.animalName
animalNumberArray[index] = a.totNumber
animalAgeArray[index] = a.avgAge
animalGrowthArray[index] = a.avgGrowth
index++
}
//call the methods for populating the charts
populatePieChart(animalNumberArray, animalNameArray)
populateBarChart(animalAgeArray)
populateLineChart(animalGrowthArray)
}
private fun populatePieChart(values: Array<Int>, labels: Array<String>) {
//an array to store the pie slices entry
val ourPieEntry = ArrayList<PieEntry>()
var i = 0
for (entry in values) {
//converting to float
var value = values[i].toFloat()
var label = labels[i]
//adding each value to the pieentry array
ourPieEntry.add(PieEntry(value, label))
i++
}
//assigning color to each slices
val pieShades: ArrayList<Int> = ArrayList()
pieShades.add(Color.parseColor("#0E2DEC"))
pieShades.add(Color.parseColor("#B7520E"))
pieShades.add(Color.parseColor("#5E6D4E"))
pieShades.add(Color.parseColor("#DA1F12"))
//add values to the pie dataset and passing them to the constructor
val ourSet = PieDataSet(ourPieEntry, "")
val data = PieData(ourSet)
//setting the slices divider width
ourSet.sliceSpace = 1f
//populating the colors and data
ourSet.colors = pieShades
ourPieChart.data = data
//setting color and size of text
data.setValueTextColor(Color.WHITE)
data.setValueTextSize(10f)
//add an animation when rendering the pie chart
ourPieChart.animateY(1400, Easing.EaseInOutQuad)
//disabling center hole
ourPieChart.isDrawHoleEnabled = false
//do not show description text
ourPieChart.description.isEnabled = false
//legend enabled and its various appearance settings
ourPieChart.legend.isEnabled = true
ourPieChart.legend.orientation = Legend.LegendOrientation.HORIZONTAL
ourPieChart.legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER
ourPieChart.legend.isWordWrapEnabled = true
//dont show the text values on slices e.g Antelope, impala etc
ourPieChart.setDrawEntryLabels(false)
//refreshing the chart
ourPieChart.invalidate()
}
private fun populateBarChart(values: Array<Int>) {
//adding values
val ourBarEntries: ArrayList<BarEntry> = ArrayList()
var i = 0
for (entry in values) {
var value = values[i].toFloat()
ourBarEntries.add(BarEntry(i.toFloat(), value))
i++
}
val barDataSet = BarDataSet(ourBarEntries, "")
//set a template coloring
barDataSet.setColors(*ColorTemplate.COLORFUL_COLORS)
val data = BarData(barDataSet)
ourBarChart.data = data
//setting the x-axis
val xAxis: XAxis = ourBarChart.xAxis
//calling methods to hide x-axis gridlines
ourBarChart.axisLeft.setDrawGridLines(false)
xAxis.setDrawGridLines(false)
xAxis.setDrawAxisLine(false)
//remove legend
ourBarChart.legend.isEnabled = false
//remove description label
ourBarChart.description.isEnabled = false
//add animation
ourBarChart.animateY(3000)
//refresh the chart
ourBarChart.invalidate()
}
private fun populateLineChart(values: Array<Int>) {
val ourLineChartEntries: ArrayList<Entry> = ArrayList()
var i = 0
for (entry in values) {
var value = values[i].toFloat()
ourLineChartEntries.add(Entry(i.toFloat(), value))
i++
}
val lineDataSet = LineDataSet(ourLineChartEntries, "")
lineDataSet.setColors(*ColorTemplate.PASTEL_COLORS)
val data = LineData(lineDataSet)
ourLineChart.axisLeft.setDrawGridLines(false)
val xAxis: XAxis = ourLineChart.xAxis
xAxis.setDrawGridLines(false)
xAxis.setDrawAxisLine(false)
ourLineChart.legend.isEnabled = false
//remove description label
ourLineChart.description.isEnabled = false
//add animation
ourLineChart.animateX(1000, Easing.EaseInSine)
ourLineChart.data = data
//refresh
ourLineChart.invalidate()
}
}
第五步:创建布局XML文件
我就不深入解释了。我们有一个根垂直布局,它有一个水平线性布局。所以我们在根布局中有两个权重相等的线性布局。
第一个内部布局有一个水平方向的两个等权重的线性布局,这使我们能够将屏幕分成两个相等的部分,我们将在那里放置饼图和柱状图(饼图和柱状图是用卡片渲染的)。折线图被放置在第二个布局中。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="600dp"
android:paddingBottom="30dp"
android:layout_marginTop="8dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:backgroundTint="@color/white"
android:layout_weight="2">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardElevation="10dp"
app:cardCornerRadius="5dp"
app:cardMaxElevation="12dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:layout_marginBottom="1dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Animal no."
android:textStyle="bold" android:textAlignment="center" android:layout_marginTop="2dp"/>
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/ourPieChart"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardElevation="10dp"
app:cardCornerRadius="5dp"
app:cardMaxElevation="12dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:layout_marginBottom="1dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Age dist."
android:textStyle="bold" android:textAlignment="center" android:layout_marginTop="2dp"/>
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/ourBarChart"
android:layout_marginTop="25dp"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.cardview.widget.CardView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="2">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Growth rate."
android:textStyle="bold" android:textAlignment="center" android:layout_marginTop="2dp"/>
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/ourLineChart"
android:layout_marginTop="20dp"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
总结
我们研究了为我们的项目设置MPAndroid图表,创建模型和数据库处理类,填充图表,以及创建用户界面。我希望你能得到一些启发,用于你的下一个项目。