效果图https://github.com/PhilJay/MPAndroidChart
首先在项目的build.gradle文件下添加如下:
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
然后在相应的module的build.gradle下添加依赖:
dependencies {
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
}
1.将MPAndroidChart设置为左右滑动的样式(缩小设置可以不用,根据情况)
Matrix matrix = new Matrix();
//x轴缩放1.5倍
matrix.postScale(1.5f, 1f);
//在图表动画显示之前进行缩放
chart.getViewPortHandler().refresh(matrix, chart, false);
// x轴执行动画
chart.animateX(2000);
2.下标数目
//下标数目
xAxis.setLabelCount(2);
其他属性
setEnabled(boolean enabled): //是否启用轴,如果禁用,关于轴的设置所有属性都将被忽略
setDrawLabels(boolean enabled):// 是否绘制标签
setDrawAxisLine(boolean enabled):// 是否绘制轴线
setDrawGridLines(boolean enabled)://是否和网格轴线
setAxisLineWidth(float f)://设置轴线的宽度
setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);//设置轴的值显示的位置
setAxisMinValue(float min): //设置轴的最小值。这样设置将不会根据提供的数据自动计算。
setGranularity(float gran)://设置Y轴最小间隔
setShowOnlyMinMax(boolean enabled)://如果启用,此轴直线式最大值和最小值架构忽略定义的标签数。
setLabelCount(int count, boolean force): //设置轴的标签数目,不是精确值,如果强制设置,可能导致轴线不均匀
setInverted(boolean enabled): //反转该轴,如果为true,最大值在底部,顶部是最小值。
setSpaceTop(float percent): //设置轴上最高位置在表中最高位置的顶部间距,占总轴的百分比。
setSpaceBottom(float percent): //设置轴上最低位置在表中最低位置的底部间距,占总轴的百分比。
setAvoidFirstLastClipping(boolean enabled)://如果设置为true,将避免图表或屏幕的边缘的第一个和最后一个轴中的标签条目被裁剪。
setSpaceBetweenLabels(int characters)://设置应该x轴标签之间的被排除在外字符,默认空间:4。
enableGridDashedLine(float lineLength, float spaceLength, float phase): //使网格线在虚线画模式,lineLength控制线长度 , spaceLength控制线之间空格长度, phase 控制起点
setDragScaleEnabled(boolean enabled): //设置是否可以拖拽,缩放
setHighlightEnabled(boolean enabled) ://设置点击value的时候,是否高亮显示
setBackgroundColor(int color): //设置整个图表视图的背景
setDescription(String desc): //右下角对图表的描述信息
setDescriptionColor(int color): //描述信息的颜色
setDescriptionPosition(float x, float y): //自定义描述信息位置.
setDescriptionTypeface(Typeface t): //自定义描述信息字体
setDescriptionTextSize(float size): //自定义描述信息字体大小, 最小值6f, 最大值16f.
setNoDataText(String desc): //设置空表的描述信息
setDrawGridBackground(boolean enabled): //是否绘制网格背景
setGridBackgroundColor(int color): //设置网格背景颜色
setDrawBorders(boolean enabled): //是否绘制边线
setBorderColor(int color)://边线颜色
setBorderWidth(float width)://边线宽度,单位dp
setMaxVisibleValueCount(int count): //设置图表绘制可见标签数量最大值. 仅在setDrawValues() 启用时生效
setMinOffset(float dp);//设置填充属性,类似与padding的效果
setScaleEnabled(false);//禁止缩放
setTouchEnabled(boolean b);//设置是否可以触摸,注意:设置false后,点击事件不再生效,也没有高亮的显示了
setValueTypeface(Typeface t)://设置字体
dataSet.setDrawValues(boolean)//是dataSet的属性,设置是否在图上显示出当前点(柱状图)的值
x轴格式化值
setValueFormatter(XAxisValueFormatter formatter):在绘制之前,动态的设置自定义格式.
public class StringAxisValueFormatter implements IAxisValueFormatter {
private List xValues;
public StringAxisValueFormatter(List xValues) {
this.xValues = xValues;
}
@Override
public String getFormattedValue(float v, AxisBase axisBase) {
if (v < 0 || v > (xValues.size() - 1)){//使得两侧柱子完全显示
return "";
}
return xValues.get((int)v);
}
}
//或者
public class MyValueFormatter implements ValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatter() {
mFormat = new DecimalFormat("###,###,##0.0"); // use one decimal
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
// write your logic here
return mFormat.format(value) + " $"; // e.g. append a dollar-sign
}
}
使用
// usage on whole data object
lineData.setValueFormatter(new MyValueFormatter());
// usage on individual dataset object
lineDataSet.setValueFormatter(new MyValueFormatter());
设置点击事件
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
@Override
public void onValueSelected(Entry e, Highlight h) {
Log.e("---->",e.getX()+" "+e.getY());
}
@Override
public void onNothingSelected() {
}
});
一般用到
public static LineChart initChart(LineChart chart,Context context) {
//提示
MyMarkerView mv = new MyMarkerView(context, R.layout.custom_marker_view);
mv.setChartView(chart); // For bounds control
chart.setMarker(mv);
// 不显示数据描述
chart.getDescription().setEnabled(false);
// 没有数据的时候,显示“暂无数据”
chart.setNoDataText("暂无数据");
// 不显示表格颜色
chart.setDrawGridBackground(false);
// 可以缩放
chart.setScaleEnabled(true);
// 不显示y轴右边的值
chart.getAxisRight().setEnabled(false);
chart.setTouchEnabled(true);
// 不显示图例
Legend legend = chart.getLegend();
legend.setEnabled(false);
// 向左偏移15dp,抵消y轴向右偏移的30dp
chart.setExtraLeftOffset(-15);
XAxis xAxis = chart.getXAxis();
// 不显示x轴
xAxis.setDrawAxisLine(false);
// 设置x轴数据的位置
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setTextColor(Color.WHITE);
xAxis.setTextSize(12);
xAxis.setGridColor(Color.parseColor("#30FFFFFF"));
// 设置x轴数据偏移量
xAxis.setYOffset(-12);
//下标数目
xAxis.setLabelCount(6);
YAxis yAxis = chart.getAxisLeft();
// 不显示y轴
yAxis.setDrawAxisLine(false);
// 设置y轴数据的位置
yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
// 不从y轴发出横向直线
yAxis.setDrawGridLines(false);
yAxis.setTextColor(Color.WHITE);
yAxis.setTextSize(12);
// 设置y轴数据偏移量
yAxis.setXOffset(30);
yAxis.setYOffset(-3);
yAxis.setAxisMinimum(0);
Matrix matrix = new Matrix();
//x轴缩放1.5倍
matrix.postScale(1.5f, 1f);
//在图表动画显示之前进行缩放
chart.getViewPortHandler().refresh(matrix, chart, false);
// x轴执行动画
chart.animateX(2000);
chart.invalidate();
return chart;
}
public static void setChartData(LineChart chart, List values) {
LineDataSet lineDataSet;
if (chart.getData() != null && chart.getData().getDataSetCount() > 0) {
lineDataSet = (LineDataSet) chart.getData().getDataSetByIndex(0);
lineDataSet.setValues(values);
chart.getData().notifyDataChanged();
chart.notifyDataSetChanged();
} else {
lineDataSet = new LineDataSet(values, "");
// 设置曲线颜色
lineDataSet.setColor(Color.parseColor("#FFFFFF"));
// 设置平滑曲线
lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
// 不显示坐标点的小圆点
lineDataSet.setDrawCircles(false);
// 不显示坐标点的数据
lineDataSet.setDrawValues(false);
// 不显示定位线
lineDataSet.setHighlightEnabled(false);
LineData data = new LineData(lineDataSet);
chart.setData(data);
chart.invalidate();
}
}
案例介绍
import android.graphics.Color
import android.graphics.Matrix
import android.os.Bundle
import android.view.MotionEvent
import android.view.Window
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
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.formatter.ValueFormatter
import com.github.mikephil.charting.listener.ChartTouchListener
import com.github.mikephil.charting.listener.OnChartGestureListener
import kotlinx.android.synthetic.main.activity_line_chart.*
/**
*@Created by wrs on 2021/8/4,9:49
*@packageName: com.dsy.tui
*@Description: 折线图
*/
class LineChartActivity : AppCompatActivity() {
var entries = arrayListOf()
var entriestwo = arrayListOf()
var week = arrayListOf()
var dataSet:LineDataSet? = null
var dataSettwo:LineDataSet? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE)//去掉标题栏
setContentView(R.layout.activity_line_chart)
//设置数据
initData()
val description = chart?.getDescription()
description?.setText("历史数据折线图"); // 设置右下角备注
//设置颜色 及 标题
dataSet = LineDataSet(entries, "收缩压") // 图表绑定数据,设置图表折现备注
dataSet?.setColor(Color.parseColor("#5B8FF9")) // 设置折线图颜色
dataSet?.setValueTextColor(Color.parseColor("#5B8FF9")) // 设置数据值的颜色
// dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);// 设置平滑曲线
dataSet?.setValueTextSize(12f);//设置折线图转择点的值的大小
dataSet?.setDrawCircles(false) //设置是否绘制圆形指示器,默认true
dataSet?.setDrawValues(false);//在点上显示数值 默认true
dataSet?.setHighLightColor(Color.parseColor("#ABB5EA")) //折线图高亮坐标线的颜色
//设置颜色 及 标题
dataSettwo = LineDataSet(entriestwo, "舒张压"); // 图表绑定数据,设置图表折现备注
dataSettwo?.setColor(Color.parseColor("#5AD8A6")); // 设置折线图颜色
dataSettwo?.setValueTextColor(Color.parseColor("#5B8FF9")); // 设置数据值的颜色
// dataSettwo.setMode(LineDataSet.Mode.CUBIC_BEZIER);// 设置平滑曲线
dataSettwo?.setValueTextSize(12f);//设置折线图转择点的值的大小
dataSettwo?.setDrawCircles(false)//设置是否绘制圆形指示器,默认true
dataSettwo?.setDrawValues(false);//在点上显示数值 默认true
dataSettwo?.setHighLightColor(Color.parseColor("#ABB5EA")) //折线图高亮坐标线的颜色
//装载数据
val lineData = LineData(dataSet,dataSettwo)
chart.data = lineData // 图表绑定数据值
// chart.animateXY(2000,1000)
chart.animateX(2000)
chart.invalidate() // 刷新图表
}
private fun initData() {
week.add("2021-01-01")
week.add("2021-01-02")
week.add("2021-01-03")
week.add("2021-01-04")
week.add("2021-01-05")
week.add("2021-01-06")
week.add("2021-01-07")
week.add("2021-01-08")
week.add("2021-01-09")
week.add("2021-01-10")
week.add("2021-01-11")
week.add("2021-01-12")
week.add("2021-01-13")
week.add("2021-01-14")
week.add("2021-01-15")
week.add("2021-01-16")
week.add("2021-01-17")
week.add("2021-01-18")
week.add("2021-01-19")
week.add("2021-01-20")
week.add("2021-01-21")
entries.add(Entry(1.0f,19.0f))
entries.add(Entry(2.0f,38.0f))
entries.add(Entry(3.0f,27.0f))
entries.add(Entry(4.0f,46.0f))
entries.add(Entry(5.0f,15.0f))
entries.add(Entry(6.0f,54.0f))
entries.add(Entry(7.0f,23.0f))
entries.add(Entry(8.0f,20.0f))
entries.add(Entry(9.0f,25.0f))
entries.add(Entry(10.0f,25.0f))
entries.add(Entry(11.0f,35.0f))
entries.add(Entry(12.0f,45.0f))
entries.add(Entry(13.0f,55.0f))
entries.add(Entry(14.0f,35.0f))
entries.add(Entry(15.0f,15.0f))
entries.add(Entry(16.0f,25.0f))
entries.add(Entry(17.0f,35.0f))
entries.add(Entry(18.0f,15.0f))
entries.add(Entry(19.0f,5.0f))
entries.add(Entry(20.0f,45.0f))
entries.add(Entry(21.0f,35.0f))
entriestwo.add(Entry(1.0f,10.0f))
entriestwo.add(Entry(2.0f,28.0f))
entriestwo.add(Entry(3.0f,7.0f))
entriestwo.add(Entry(4.0f,56.0f))
entriestwo.add(Entry(5.0f,45.0f))
entriestwo.add(Entry(6.0f,24.0f))
entriestwo.add(Entry(7.0f,35.0f))
entriestwo.add(Entry(8.0f,25.0f))
entriestwo.add(Entry(9.0f,50.0f))
entriestwo.add(Entry(10.0f,39.0f))
entriestwo.add(Entry(11.0f,28.0f))
entriestwo.add(Entry(12.0f,18.0f))
entriestwo.add(Entry(13.0f,38.0f))
entriestwo.add(Entry(14.0f,26.0f))
entriestwo.add(Entry(15.0f,35.0f))
entriestwo.add(Entry(16.0f,24.0f))
entriestwo.add(Entry(17.0f,45.0f))
entriestwo.add(Entry(18.0f,25.0f))
entriestwo.add(Entry(19.0f,18.0f))
entriestwo.add(Entry(20.0f,50.0f))
entriestwo.add(Entry(21.0f,35.0f))
chart.setNoDataText("暂无数据")
// 不可以缩放
chart.setScaleEnabled(false);
chart.setPinchZoom(false);
// chart?.setMaxVisibleValueCount(60); //最大显示的个数。超过60个将不再显示
//设置一页最大显示个数为6,超出部分就滑动
// val ratio = entries.size / 18;
chart.zoom(2.5f,1f,0f,0f);//显示的时候 是 按照多大的比率缩放显示 1f表示不放大缩小
//是否展示网格线
chart.setDrawGridBackground(false)
val valueFormatter: ValueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return "" + week.get(value.toInt() - 1)
}
}
//设置markerview
chart.marker = XYMarkerView(this,chart,valueFormatter,entries,entriestwo)
chart.setScaleMinima(1f,1f)
//x轴设置
val xAxis = chart.getXAxis()
// 不显示x轴
xAxis.setDrawAxisLine(true)
// 设置x轴数据的位置
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.textColor = Color.WHITE
xAxis.textSize = 6f
xAxis.gridColor = Color.parseColor("#3E466D")
// xAxis.setAxisMinimum(0f);
xAxis.setGranularity(1f);//设置Y轴最小间隔
xAxis.axisLineColor = Color.parseColor("#3E466D")
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); // 让x轴在下面
xAxis.setGridColor(getResources().getColor(android.R.color.transparent));
// xAxis.setLabelRotationAngle(-30f); //对X轴进行一定角度的旋转,看着有立体效果,还能减小字体重叠
xAxis?.valueFormatter = valueFormatter
//y轴设置
val leftYAxis = chart.getAxisLeft();
val rightYaxis = chart.getAxisRight();
//保证Y轴从0开始,不然会上移一点
leftYAxis.textColor = Color.WHITE
leftYAxis.setDrawLabels(true)
leftYAxis.axisMinimum = 0f
leftYAxis.axisMaximum = 60f
leftYAxis.axisLineColor = getResources().getColor(android.R.color.transparent)
// leftYAxis.setEnabled(false); // 隐藏左边 的坐标轴
rightYaxis.setEnabled(false); // 隐藏右边 的坐标轴
}
}
布局
自定义markerview
import android.content.Context;
import android.widget.TextView;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.MarkerView;
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.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;
import java.text.DecimalFormat;
import java.util.List;
public class XYMarkerView extends MarkerView {
private TextView tvTime;
private TextView tvChart;
private TextView tvChartTwo;
private DecimalFormat format;
private List entries;
private List entriesTwo;
private LineChart chart;
private IAxisValueFormatter xAxisValueFormatter;
public XYMarkerView(Context context, LineChart chart, IAxisValueFormatter xAxisValueFormatter, List entries, List entriesTwo) {
super(context, R.layout.custom_marker_view);
tvTime = (TextView) findViewById(R.id.tvTime);
tvChart = (TextView) findViewById(R.id.tvChart);
tvChartTwo = (TextView) findViewById(R.id.tvChartTwo);
format = new DecimalFormat("###.0");
this.entries = entries;
this.xAxisValueFormatter = xAxisValueFormatter;
this.entriesTwo = entriesTwo;
this.chart = chart;
}
//回调函数每次MarkerView重绘,可以用来更新内容(用户界面)
@Override
public void refreshContent(Entry e, Highlight highlight) {
LineData lineData = chart.getLineData();//得到已经绘制成型的折线图的数据
LineDataSet set = (LineDataSet)lineData.getDataSetByIndex(0);//获取第一条折线图Y轴数据
LineDataSet set2 = (LineDataSet)lineData.getDataSetByIndex(1);//获取第二条折线图Y轴数据
int DataSetIndex = highlight.getDataSetIndex();//获取点击的是哪条折线上的交叉点,0就是第一条,以此类推
int index;
if (DataSetIndex == 0){
index = set.getEntryIndex(e);//根据点击的该条折线的点,获取当前Y轴数据对应的index值,
}else {
index = set2.getEntryIndex(e);//根据点击的该条折线的点,获取当前Y轴数据对应的index值,
}
//根据index值,分别获取当前X轴上对应的两条折线的Y轴的值
Entry entry = set.getEntryForIndex(index);
Entry entry2 = set2.getEntryForIndex(index);
tvTime.setText(xAxisValueFormatter.getFormattedValue(e.getX(), null));
tvChart.setText("" + entry.getY());
tvChartTwo.setText("" + entry2.getY());
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {//可以调节markView的位置,根据项目的需求
return new MPPointF(-(getWidth() / 2), -getHeight());
}
}
自定义markerview 的布局