简介:MPAndroidChart 是一个Android非常强大的图标库,包括折线图,柱状图,饼图,雷达图,散列图等,官方github地址请戳这里
一.说了这么多,咱先看看 效果图:
2.博主主要以这个折线图为列,讲讲具体实现过程,首先看到这个效果图,我之前以为很简单,所以刚开始 自己自定义了一个,后来发现问题挺多,所以在github找了一番资料,最终使用MPAndroidChart库。
3.添加依赖
(在主project的build.gradle中添加依赖)
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
(然后在app的build.gradle中添加依赖)
dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.2'
}
4.在xml 布局中使用
5.Java类实现代码
@BindView(R.id.ll_title_root)
LinearLayout llTitleRoot;
//心率
@BindView(R.id.linCart)
LineChart mLineCharHeart;
//呼吸率
@BindView(R.id.linCartBreath)
LineChart mLinCartBreath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
ButterKnife.bind(this);
}
@Override
protected void initView() {
mUserInfoDao = new UserInfoDao(this);
mDataList = new ArrayList<>();
mTimeList = new ArrayList<>();
//这个集合是从本地数据获取的,你们使用的时候之前替换数据源就行。
mDataList = mUserInfoDao.queryEcgAll();
//添加时间集合
if (mDataList != null && mDataList.size() > 0) {
for (int i = 0; i < mDataList.size(); i++) {
mTimeList.add(mDataList.get(i).getTime());
}
}
initLinartData(mLineCharHeart, 1);//心率
initLinartData(mLinCartBreath, 2);//呼吸率
}
/**
* 折线图方法
*/
private void initLinartData(LineChart mLineChar, int type) {
//后台绘制
mLineChar.setDrawGridBackground(false);
//设置描述文本
mLineChar.getDescription().setEnabled(false);
//设置支持触控手势
mLineChar.setTouchEnabled(true);
mLineChar.getXAxis().setDrawGridLines(false);// 是否绘制网格线,默认true
mLineChar.getAxisRight().setEnabled(false);// 不绘制右侧的轴线
mLineChar.getXAxis().setAvoidFirstLastClipping(false);
mLineChar.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);//去掉上面x
// mLineChar.setBorderWidth(3f); //设置 chart 边界线的宽度,单位 dp。
// //设置是否可以拖拽
mLineChar.setDragEnabled(true);
//是否缩放
mLineChar.setScaleEnabled(false);
//如果禁用,扩展可以在x轴和y轴分别完成
mLineChar.setPinchZoom(true);
mLineChar.setNoDataText("暂无数据"); // 没有数据时样式
//这个三个属性是设置LineChar间距的,如果不设置 数据多的时候X轴标签文字会显示不全 ,切记 切记 切记!!!
mLineChar.setExtraBottomOffset(20f);
mLineChar.setExtraRightOffset(30f);
mLineChar.setExtraLeftOffset(10f);//间距
// mLineChar.setVisibleXRangeMaximum(4);
Transformer trans = mLineChar.getTransformer(YAxis.AxisDependency.LEFT);
//自定义X轴标签位置
mLineChar.setXAxisRenderer(new CustomXAxisRenderer(mLineChar.getViewPortHandler(),
mLineChar.getXAxis(), trans));
// mLineChar.setMaxVisibleValueCount(0); // 数据点上显示的标签,最大数量,默认100。
// *************************轴****************************** //
// 由四个元素组成:
// 标签:即刻度值。也可以自定义,比如时间,距离等等,下面会说一下;
// 轴线:坐标轴;
// 网格线:垂直于轴线对应每个值画的轴线;
// 限制线:最值等线。
XAxis xAxis = mLineChar.getXAxis(); // 获取X轴
YAxis yAxis = mLineChar.getAxisLeft(); // 获取Y轴,mLineChart.getAxis(YAxis.AxisDependency.LEFT);也可以获取Y轴
//x坐标轴设置 下面几个属性很重要
xAxis.setGranularity(1f);//设置最小间隔,防止当放大时,出现重复标签。
xAxis.setLabelCount(5);//设置x轴显示的标签个数
xAxis.setAxisLineWidth(1f);//设置x轴宽度, ...其他样式、
// xAxis.setTextSize(20f);设置X轴字体大小
xAxis.setCenterAxisLabels(false);//x轴居中显示
// xAxis.setDrawAxisLine(true);
//y轴设置
yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);//y轴标签绘制的位置
yAxis.setDrawGridLines(false);//不绘制y轴格网线
xAxis.setAxisMaximum(5); // 此轴能显示的最大值;
xAxis.resetAxisMaximum(); // 撤销最大值;
xAxis.setAxisMinimum(1); // 此轴显示的最小值;
xAxis.resetAxisMinimum(); // 撤销最小值;
yAxis.setSpaceTop(10); // 设置最大值到图标顶部的距离占所有数据范围的比例。默认10,y轴独有
// 上面的右图是以下代码设置后的效果图
yAxis.setStartAtZero(false);
// // 算法:比例 = (y轴最大值 - 数据最大值)/ (数据最大值 - 数据最小值) ;
// 用途:可以通过设置该比例,使线最大最小值不会触碰到图标的边界。
// 注意:设置一条线可能不太好看,mLineChart.getAxisRight().setSpaceTop(34)也设置比较好;同时,如果设置最小值,最大值,会影响该效果
// yAxis.setSpaceBottom(10); // 同上,只不过是最小值距离底部比例。默认10,y轴独有
// yAxis.setShowOnlyMinMax(true); // 没找到。。。,true, 轴上只显示最大最小标签忽略指定的数量(setLabelCount,如果forced = false).
//yAxis.setLabelCount(4, false); // 纵轴上标签显示的数量,数字不固定。如果force = true,将会画出明确数量,但是可能值导致不均匀,默认(6,false)
// yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART); // 标签绘制位置。默认再坐标轴外面
// xAxis.setGranularity(1); // 设置X轴值之间最小距离。正常放大到一定地步,标签变为小数值,到一定地步,相邻标签都是一样的。这里是指定相邻标签间最小差,防止重复。
//yAxis.setGranularity(1); // 同上
yAxis.setGranularityEnabled(false); // 是否禁用上面颗粒度限制。默认false
// 轴颜色
yAxis.setTypeface(null); // 标签字体
//yAxis.removeLimitLine(ll); // 移除指定的限制线,还有其他的几个移除方法
yAxis.setDrawLimitLinesBehindData(false); // 限制线在数据之后绘制。默认为false
// X轴更多属性
// xAxis.setLabelRotationAngle(45); // 标签倾斜
// xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); // X轴绘制位置,默认是顶部
// Y轴更多属性
//set1.setAxisDependency(YAxis.AxisDependency.LEFT); // 设置dataSet应绘制在Y轴的左轴还是右轴,默认LEFT
yAxis.setDrawZeroLine(false); // 绘制值为0的轴,默认false,其实比较有用的就是在柱形图,当有负数时,显示在0轴以下,其他的图这个可能会看到一些奇葩的效果
yAxis.setZeroLineWidth(10); // 0轴宽度
yAxis.setZeroLineColor(Color.BLUE); // 0轴颜色
//图例设置
Legend legend = mLineChar.getLegend();
legend.setEnabled(false);//隐藏图列
//legend.setWordWrapEnabled(true);//标签是否换行
ArrayList values = new ArrayList();
if (type == 1) {//心率
yAxis.setAxisMinValue(40);
yAxis.setAxisMaxValue(120);
// 限制线
initECgData(yAxis, 60f, 90f, "心率过速", "心率过缓");
//设置数据数据
if (mDataList!=null&&mDataList.size()>0){
for (int i = 0; i < mDataList.size(); i++) {
values.add(new Entry(i, mDataList.get(i).getHeart()));
}
}
} else if (type == 2) {//呼吸率
yAxis.setAxisMinValue(0);
yAxis.setAxisMaxValue(40);
initECgData(yAxis, 10f, 20f, "呼吸过速", "呼吸过缓");
//设置数据数据
if (mDataList!=null&&mDataList.size()>0){
for (int i = 0; i < mDataList.size(); i++) {
values.add(new Entry(i, mDataList.get(i).getBreath()));
}
}
}
//设置一页最大显示个数为6,超出部分就滑动
float ratio = (float) values.size() / (float) 5;
//显示的时候是按照多大的比率缩放显示,1f表示不放大缩小
mLineChar.zoom(ratio, 0f, 0, 0);
if (mTimeList.size()>0){
xAxis.setValueFormatter(new StringAxisValueFormatter(mTimeList));
}
//xAxis.setValueFormatter(new MyXFormatter(mDataTime));
//
//设置数据
if (values.size()>0){
setData(values, mLineChar);
}
//默认动画
// mLineChar.animateX(2500);
//刷新
mLineChar.invalidate();
//传递数据集
}
private void initECgData(YAxis yAxis, float minLim, float maxLim, String labelone, String labeltwo) {
// 限制线
LimitLine lim2 = new LimitLine(minLim, labeltwo); // 创建限制线, 这个线还有一些相关的绘制属性方法,自行看一下就行,没多少东西。
yAxis.addLimitLine(lim2);
// 添加限制线到轴上
LimitLine lim1 = new LimitLine(maxLim, labelone); // 创建限制线, 这个线还有一些相关的绘制属性方法,自行看一下就行,没多少东西。
yAxis.addLimitLine(lim1);
}
//自定义X轴数据
public class StringAxisValueFormatter implements IAxisValueFormatter {
private List mTimeList;
public StringAxisValueFormatter(List mTimeList) {
this.mTimeList = mTimeList;
}
@Override
public String getFormattedValue(float v, AxisBase axisBase) {
if (v < 0 || v > (mTimeList.size() - 1)) {//使得两侧柱子完全显示
return "";
}
return mTimeList.get((int) v);
}
}
//自定义Y轴数据
public class AxisValueFormatter implements IAxisValueFormatter {
private List mYaxitData;
public AxisValueFormatter(List mYaxitData) {
this.mYaxitData = mYaxitData;
}
@Override
public String getFormattedValue(float v, AxisBase axisBase) {
if (v < 0 || v > (mYaxitData.size() - 1)) {
return "";
}
return mYaxitData.get((int) v) + "%";
}
}
//传递数据集
private void setData(ArrayList values, LineChart mLineChar) {
if (mLineChar.getData() != null && mLineChar.getData().getDataSetCount() > 0) {
dataSets = (LineDataSet) mLineChar.getData().getDataSetByIndex(0);
dataSets.setValues(values);
mLineChar.getData().notifyDataChanged();
mLineChar.notifyDataSetChanged();
} else {
// 创建一个数据集,并给它一个类型
dataSets = new LineDataSet(values, "血压测量");
// 在这里设置线
// set1.enableDashedLine(10f, 5f, 0f); 虚线
// set1.enableDashedHighlightLine(10f, 5f, 0f);
dataSets.setColor(Color.parseColor("#0AA4EC"));
dataSets.setCircleColor(Color.parseColor("#0AA4EC"));
dataSets.setLineWidth(1f);
dataSets.setCircleRadius(3f);
dataSets.setDrawCircleHole(false);
// set1.setValueTextSize(9f);
dataSets.setDrawFilled(false);//折线图背景
// set1.setFormLineWidth(1f);
// set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
// set1.setFormSize(15.f);
if (Utils.getSDKInt() >= 18) {
// 填充背景只支持18以上
//Drawable drawable = ContextCompat.getDrawable(this, R.mipmap.ic_launcher);
//set1.setFillDrawable(drawable);
//set1.setFillColor(Color.YELLOW);
} else {
// set1.setFillColor(Color.BLACK);
}
ArrayList mDataSets = new ArrayList();
//添加数据集
mDataSets.add(dataSets);
//创建一个数据集的数据对象
LineData data = new LineData(dataSets);
// data.setDrawValues(false);
//谁知数据
mLineChar.setData(data);
}
}
/**
* 修改源码使得 x轴坐标换行 ,下面属性自己可以调整
*/
public class CustomXAxisRenderer extends XAxisRenderer {
public CustomXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
super(viewPortHandler, xAxis, trans);
}
@Override
protected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {
float labelHeight = mXAxis.getTextSize();
float labelInterval = 5f;
String[] labels = formattedLabel.split(" ");
Paint mFirstLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFirstLinePaint.setColor(0xFF9b9b9b);
mFirstLinePaint.setTextAlign(Paint.Align.LEFT);
mFirstLinePaint.setTextSize(Utils.convertDpToPixel(10f));
mFirstLinePaint.setTypeface(mXAxis.getTypeface());
Paint mSecondLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSecondLinePaint.setColor(0xFF9b9b9b);
mSecondLinePaint.setTextAlign(Paint.Align.LEFT);
mSecondLinePaint.setTextSize(Utils.convertDpToPixel(10f));
mSecondLinePaint.setTypeface(mXAxis.getTypeface());
if (labels.length > 1) {
Utils.drawXAxisValue(c, labels[0], x, y, mFirstLinePaint, anchor, angleDegrees);
Utils.drawXAxisValue(c, labels[1], x, y + labelHeight + labelInterval, mSecondLinePaint, anchor, angleDegrees);
} else {
Utils.drawXAxisValue(c, formattedLabel, x, y, mFirstLinePaint, anchor, angleDegrees);
}
}
}
6.代码不算多,到这里就写完了,具体效果,各位小伙伴可以自己写个demo集成下 上面代码也有注释 很好理解,这里稍微解释下,比如如何让X轴坐标换行,具体属性 源码里面没提供接口出来,需要自己重写方法去实现,水平滑动,只要设置一下最大值和最小值就行,但是同时你要设置下 支持触摸,不然会没效果的,好了 今天就分享到这里,有问题欢迎随时留言。