1.引入依赖
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
2.需求效果图
3.
设置Linechart数据
private fun initLineChart(list: List<HourStatistics>) {
mLinechart.description.isEnabled = false
mLinechart.legend.direction = Legend.LegendDirection.LEFT_TO_RIGHT
mLinechart.legend.orientation = Legend.LegendOrientation.HORIZONTAL
mLinechart.legend.verticalAlignment = Legend.LegendVerticalAlignment.TOP
mLinechart.setTouchEnabled(true)
mLinechart.setDrawGridBackground(false)
// enable scaling and dragging
mLinechart.isDragEnabled = false
mLinechart.setScaleEnabled(false)
// chart.setScaleXEnabled(true);
// chart.setScaleYEnabled(true);
// force pinch zoom along both axis
mLinechart.setPinchZoom(false)
// // Y-Axis Style // //
val yAxis: YAxis = mLinechart.axisLeft
// disable dual axis (only use LEFT axis)
mLinechart.axisRight.isEnabled = false
yAxis.setDrawLimitLinesBehindData(true)
yAxis.setDrawZeroLine(false)
/**
* 绘制虚线网格线,
* DashPathEffect:
* @params:new float[]{30,20,30,20} 先绘制30px实线,再绘制20px透明,再绘制30px实线,再绘制20px透明
* @params:0 偏移量,若为20,则效果为:先绘制10px实线,再绘制20px透明,再绘制30px实线,再绘制20px透明
*/
yAxis.setGridDashedLine(DashPathEffect(floatArrayOf(30f, 20f, 30f, 20f), 0F))
mLinechart.axisLeft.setDrawLabels(true)
mLinechart.axisLeft.setDrawTopYLabelEntry(true)
mLinechart.axisLeft.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART)
var minY= list[0].menCountByHour
var maxY=0
list.forEach {
var maleEntry=Entry()
maleEntry.x= it.reportHour.toFloat()
maleEntry.y=it.menCountByHour.toFloat()
var femaleEntry=Entry()
femaleEntry.x= it.reportHour.toFloat()
femaleEntry.y=it.womanCountByHour.toFloat()
xDataMale.add(maleEntry)
xDatasFemale.add(femaleEntry)
//获取最小值
if(it.menCountByHour<minY || it.womanCountByHour<minY){
if (it.menCountByHour<it.womanCountByHour){
minY = it.menCountByHour
}else if (it.menCountByHour>it.womanCountByHour){
minY = it.womanCountByHour
}else{
minY = it.menCountByHour
}
}
//获取最大值
if(it.menCountByHour> maxY || it.womanCountByHour> maxY){
if (it.menCountByHour>it.womanCountByHour){
maxY=it.menCountByHour
}else if (it.menCountByHour<it.womanCountByHour){
maxY=it.womanCountByHour
}else{
maxY=it.menCountByHour
}
}
}
yAxis.axisMinimum = (minY/10 *10).toFloat() //设置Y轴最小值
yAxis.axisMaximum = (((maxY/10)+1)*10).toFloat() //设置Y轴最大值
yAxis.labelCount = 10 //设置Y轴标签数
yAxis.granularity = (yAxis.axisMaximum-yAxis.axisMinimum)/10 //设置Y轴标签单位间隔
val xAxis: XAxis = mLinechart.xAxis // 获取X轴
xAxis.position = XAxis.XAxisPosition.BOTTOM // X轴绘制位置,默认是顶部
xAxis.setDrawGridLines(false) //不绘制x轴格网线
//x坐标轴设置 下面几个属性很重要
xAxis.axisMinimum = 0f //设置x轴最小值
xAxis.axisMaximum = 24f //设置x轴最大值
xAxis.labelCount = 11 //设置x轴显示的标签个数
xAxis.granularity = 2f //设置最小间隔,
xAxis.axisLineWidth = 1f //设置x轴宽度, ...其他样式、
xAxis.setDrawLabels(true)
xAxis.setCenterAxisLabels(false) //x轴居中显示
xAxis.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
if (value==24.0f){
return ""
}else{
return value.toInt().toString()
}
}
}
//y轴设置
yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART) //y轴标签绘制的位置
yAxis.setDrawGridLines(true) // 显示Y轴网格线
yAxis.gridColor = Color.BLACK // 线条颜色
yAxis.gridLineWidth = 1f // 线条宽度
yAxis.enableGridDashedLine(10f, 10f, 0f) // 线条为虚线
yAxis.valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return if (value > 0 ) {
value.toInt().toString()
} else {
""
}
}
}
val dataSets1: LineDataSet
val dataSets2: LineDataSet
//设置数据
if (mLinechart.data != null && mLinechart.data.dataSetCount > 0) {
dataSets1 = mLinechart.data.getDataSetByIndex(0) as LineDataSet
dataSets1.values = xDataMale
dataSets2 = mLinechart.data.getDataSetByIndex(1) as LineDataSet
dataSets2.values = xDatasFemale
mLinechart.data.notifyDataChanged()
mLinechart.notifyDataSetChanged()
} else {
//创建一个数据集,并给它一个类型
dataSets1 = LineDataSet(xDataMale, "男厕客流量" )
dataSets1.setDrawCircles(false) //不绘制圆点
dataSets1.setDrawCircleHole(true) //是否实心
dataSets1.setDrawValues(false) //是否显示Y轴的值
dataSets1.color = resources.getColor(R.color.main_color)
dataSets1.lineWidth = 1f
dataSets1.setCircleColor(resources.getColor(R.color.main_color))
dataSets1.valueTextSize = 13f
dataSets1.valueTextColor = resources.getColor(R.color.main_color)
dataSets1.mode = LineDataSet.Mode.CUBIC_BEZIER
dataSets1.fillColor = resources.getColor(R.color.main_color) // 设置区域内填充颜色
dataSets1.fillAlpha = 100 // 设置区域内填充颜色的透明度
dataSets1.setDrawFilled(true)
// 设置 FillFormatter 来定义填充区域的样式
dataSets1.fillFormatter = object : DefaultFillFormatter() {
override fun getFillLinePosition(dataSet: ILineDataSet, dataProvider: LineDataProvider): Float {
return mLinechart.axisLeft.axisMinimum // 设置填充区域的底部位置
}
}
dataSets2 = LineDataSet(xDatasFemale, "女厕客流量" )
dataSets2.setDrawCircles(false) //不绘制圆点
dataSets2.setDrawCircleHole(true) //是否实心
dataSets2.setDrawValues(false) //是否显示Y轴的值
dataSets2.color = resources.getColor(R.color.color_4CAF50)
dataSets2.lineWidth = 1f
dataSets2.setCircleColor(resources.getColor(R.color.color_4CAF50))
dataSets2.valueTextSize = 13f
dataSets2.valueTextColor = resources.getColor(R.color.color_4CAF50)
dataSets2.mode = LineDataSet.Mode.CUBIC_BEZIER
dataSets2.fillColor = resources.getColor(R.color.color_4CAF50) // 设置区域内填充颜色
dataSets2.fillAlpha = 100 // 设置区域内填充颜色的透明度
dataSets2.setDrawFilled(true)
dataSets2.fillFormatter = object : DefaultFillFormatter() {
override fun getFillLinePosition(dataSet: ILineDataSet, dataProvider: LineDataProvider): Float {
return mLinechart.axisLeft.axisMinimum // 设置填充区域的底部位置
}
}
//创建一个数据集的数据对象
val data = LineData(dataSets1,dataSets2)
//设置数据
mLinechart.data = data
val mv = CustomMarkerView(mLinechart,requireActivity(),R.layout.custom_marker_linechart);
mLinechart.marker = mv
mLinechart.setOnChartValueSelectedListener(object :OnChartValueSelectedListener{
override fun onValueSelected(e: Entry?, h: Highlight?) {}
override fun onNothingSelected() {}
})
}
mLinechart.invalidate()
}
创建MarkerView
// 创建一个 MarkerView 类来自定义显示选中点数值的视图
class CustomMarkerView(lineChartView: LineChart,context: Context?, layoutResource: Int) : MarkerView(context, layoutResource) {
private val tv_1: TextView
private val tv_2: TextView
private val tv_3: TextView
private var chartView: LineChart
// 在绘制 MarkerView 时回调,可以在此方法中设置显示的内容
override fun refreshContent(entry: Entry, highlight: Highlight) {
val xValue =entry.x // 获取所选点的X轴值
val dataSets:List<ILineDataSet> = chartView.lineData.dataSets
val yValue0= dataSets[0].getEntryForXValue(xValue,Float.NaN)
val yValue1= dataSets[1].getEntryForXValue(xValue,Float.NaN)
tv_1.text="${xValue.toInt()}点"
tv_2.text="${yValue0.y.toInt()}"
tv_3.text="${yValue1.y.toInt()}"
// 获取所有数据集
super.refreshContent(entry, highlight)
}
// 在 MarkerView 位置发生改变时回调,可以在此方法中调整位置
fun markerPositionChanged(marker: Marker?) {
// 自定义调整位置逻辑
}
override fun getOffset(): MPPointF? { //调整MarkerView位置
return MPPointF((-(width / 2)-60).toFloat(), (-height - 30).toFloat())
}
init {
tv_1 = findViewById(R.id.tv_1)
tv_2 = findViewById(R.id.tv_2)
tv_3 = findViewById(R.id.tv_3)
chartView=lineChartView
}
}
实体类
data class HourStatistics(
@Expose
var menCountByHour: Int,
@Expose
val reportHour: Int,
@Expose
var womanCountByHour: Int
)
MarkerView布局 custom_marker_linechart
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_rec_c5all"
android:paddingHorizontal="10dp"
android:paddingVertical="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp"
android:text="0点"/>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_marginVertical="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@color/main_color"/>
<TextView
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp"
android:text="男厕客流量:"/>
<TextView
android:id="@+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:textSize="13sp"
android:text="0"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@color/color_4CAF50"/>
<TextView
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13sp"
android:text="女厕客流量:"/>
<TextView
android:id="@+id/tv_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:textSize="13sp"
android:text="0"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
效果图