如何使用MPAndroid图表库创建一个数据可视化仪表板

198 阅读10分钟

使用MPAndroid图表库创建一个数据可视化仪表板

用户从信息中获得洞察力的最简单方法是通过数据可视化。数据可视化最常见的工具是使用图表。

本教程将使用Kotlin和开源图表库MPAndroidChart ,创建一个简单的管理仪表板,允许用户使用三种常用的图表查看数据:饼图、条形图和线图。

该应用程序将模拟游戏公园中的野生动物数据。对于数据,我们将从一个SQLite数据库中获取。数据源并不重要,你可以使用任何数据源。它可以通过JSON、Room持久化库、简单数组、本地存储等从任何API中获取。我们将在最后实现这个目标(该布局仅配置为轻型模式)。

Screenshot

前提条件

  1. Kotlin编程语言的基本知识,以及它在开发Android应用程序中的使用。
  2. 在你的机器上安装Android StudioIntellijIDEA(为Android开发而配置)。
  3. SQLite数据库的知识。同样,这也是不必要的,因为你可以使用任何其他的数据源。
  4. 一般面向对象的编程(OOP)概念。

目标

在本文结束时,读者应该熟练掌握。

  • 创建一个SQLite数据库。
  • 使用MPAndroid图表库将图表添加到我们的项目中。
  • 使用从SQLite数据库加载的数据填充图表。

第一步:设置库

创建一个新的应用程序后,按照下面的方法修改你的Gradle文件。

  1. 在你的应用级build.gradle 文件中添加以下依赖关系。
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
  1. 最后,在项目级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图表,创建模型和数据库处理类,填充图表,以及创建用户界面。我希望你能得到一些启发,用于你的下一个项目。