之前有那么一段时间比较 “凉~”
以下一段内容是在下 - 微微的抱怨,可跳过~
因为项目需求 ,需要一个折线图的经营报表 ,所以我找到了MPAndroidChart 这个三方架子,毕竟是GitHub Stars 25K以上的大佬框架~
但是使用中却遇到了挺多的麻烦,因为成型较早,扩展性强,但是文档相对较缺失(虽然有一个api网站维护,但是依旧找Api很费事儿…),所以导致使用的时候不是很方便!
为了解决折线图这个需求,我看了十几篇博客,用了差不多3天的时间,因为开发中发生的很多问题需要逐一解决~
故此在我实现项目需求后,我抽时间好好整理了一下使用方式,同时记录了开发中遇到的问题,在简单封装后我写了此篇blog,希望可以帮到你,让你只需要半天就可以解决这个需求 - - !
效果预览
正文
bulid 依赖导入
- build(Project)
/**导入 maven { url "https://jitpack.io" } 依赖*/
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
- build(app)
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
代码解析大全
MainActivity(除了数据之外,其他直接copy一般就可以用了) :
package com.advance.yongliu.linechartfuture;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
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 java.util.ArrayList;
import java.util.List;
import static com.github.mikephil.charting.components.YAxis.YAxisLabelPosition.OUTSIDE_CHART;
public class MainActivity extends AppCompatActivity {
private TextView mContent;
private LineChart mLineChart;
/**
* X轴的标注
*/
String[] dataX1 = {"2010-22", "2011-22", "2012-22", "2021-22", "2026-22", "2025-23", "2025-22"};
/**
* Y轴的标注
*/
String[] dataY1 = {"530", "132", "230", "33", "10", "3245555", "22"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContent = findViewById(R.id.tv_content);
mLineChart = findViewById(R.id.linechart);
//设置x轴、y轴数据,同时绑定 折线图控件 - -
addChartView(dataX1, dataY1, mLineChart);
dataListener(dataX1);
}
/**
* 监听用户滑动时的各种数据
*/
private void dataListener(String[] xData) {
//绑定滑动时的数据UI显示
MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view, xData);
// For bounds control
mv.setChartView(mLineChart);
// Set the marker to the chart
mLineChart.setMarker(mv);
//获取各种数据的回调监听!这个关键哦!!!
mv.setDataCallback(new MyMarkerView.DataCallback() {
@Override
public void setData(String x, String y, int position) {
//滑动时候的数据返回!!!
mContent.setText("当前x轴的数据:" + x + "\n" + "当前y轴的数据:" + y + "\n" + "当前position的数据:" + position);
}
});
}
/**
* 初始化x轴、y轴显示配置
*/
private void addChartView(final String[] xData, final String[] yData, LineChart mLineChart) {
XAxis xAxis = mLineChart.getXAxis();
//x轴坐标绘制在什么方位
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//缩放的时候有用,比如放大的时候,我不想把横轴的月份再细分
xAxis.setGranularity(1f);
xAxis.setGridColor(Color.BLUE);
xAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return xData[(int) value % xData.length];
}
});
//设置坐标轴那条线的宽度
xAxis.setAxisLineWidth(0f);
//是否显示坐标轴那条轴
xAxis.setDrawAxisLine(true);
//是不是显示轴上的刻度
xAxis.setDrawLabels(true);
//强制有多少个刻度
xAxis.setLabelCount(xData.length);
xAxis.setTextColor(Color.parseColor("#999999"));
xAxis.setDrawGridLines(false);
YAxis yAxis = mLineChart.getAxisLeft();
yAxis.setEnabled(true);
//设置从Y轴值
yAxis.setAxisMinimum(0);
yAxis.setDrawLimitLinesBehindData(true);
yAxis.setDrawAxisLine(false);
//Y轴数据
yAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
int IValue = (int) value;
return String.valueOf(IValue);
}
});
//不显示网格线
yAxis.setDrawGridLines(true);
//坐标轴绘制在图表的内侧
yAxis.setPosition(OUTSIDE_CHART);
yAxis.setTextColor(Color.parseColor("#999999"));
//设置Y轴坐标之间的最小间隔
yAxis.setGranularity(1);
//这个玩意好像有坐标轴enable的时候是不可用的
yAxis.setSpaceBottom(10f);
yAxis.setLabelCount(6);
// 每个DataSet是对应一条线上的所有点(相对于折线图来说),多条线就创建多个 LineData
mLineChart.setData(new LineData());
addLineDataSet(yData, mLineChart);
}
/**
* 初始化"折线图"配置 ,填充y轴数据进行渲染
*/
private void addLineDataSet(String[] data, LineChart mLineChart) {
//数据填充
List<Entry> entries = new ArrayList<>();
for (int i = 0; i < data.length; i++) {
String chartData = data[i];
entries.add(new Entry(i, Float.parseFloat(chartData)));
}
//折线图基础配置 每一个mLineChartData可以看成一条独立的折线,可以设置多条不一样的折线在同一个表内展示
LineData mLineChartData = mLineChart.getData();
if (mLineChartData != null) {
final LineDataSet set = new LineDataSet(entries, null);
set.setLineWidth(1.5f);
set.setCircleRadius(3.5f);
set.setColor(Color.parseColor("#3F7FCD"));
set.setDrawCircleHole(false);
set.setHighlightLineWidth(1.5f);
set.setValueTextSize(10f);
//节点不显示具体数值
set.setDrawValues(false);
//设置是否显示圆点
set.setDrawCircles(false);
//圆点的颜色
set.setCircleColor(Color.parseColor("#4081D6"));
set.setValueTextColor(Color.parseColor("#4081D6"));
//填充折线图折线和坐标轴之间
set.setDrawFilled(true);
//填充可以设置渐变填充一个Drawable,或者仅仅填充颜色
set.setFillColor(Color.parseColor("#CDDDF2"));
mLineChartData.addDataSet(set);
mLineChartData.notifyDataChanged();
mLineChart.notifyDataSetChanged();
//这行代码必须放到这里,这里设置的是图表这个视窗能显示,x坐标轴,从最大值到最小值之间
mLineChart.setVisibleXRangeMaximum(data.length);
mLineChart.invalidate();
}
//影藏底部色块
Legend legend = mLineChart.getLegend();
legend.setEnabled(false);
mLineChart.getAxisRight().setEnabled(false);
//图表描述文字
Description description = new Description();
description.setText("");
//右下角说明文字
mLineChart.setDescription(null);
mLineChart.setNoDataText("正在加载中,请稍后");
//四周是不是有边框
mLineChart.setDrawBorders(false);
mLineChart.setBorderWidth(0.5f);
//边框颜色,默认黑色?
mLineChart.setBorderColor(Color.parseColor("#999999"));
//允许触摸
mLineChart.setTouchEnabled(true);
// 启用/禁用拖动(平移)图表。
mLineChart.setDragEnabled(true);
//禁止x轴y轴同时进行缩放
mLineChart.setPinchZoom(false);
//启用/禁用缩放图表上的两个轴。
mLineChart.setScaleEnabled(false);
//设置为false以禁止通过在其上双击缩放图表。
mLineChart.setDoubleTapToZoomEnabled(false);
}
}
MyMarkerView(框架内的一个自定义控件,用于监听用户滑动时触发的数据)
package com.advance.yongliu.linechartfuture;
import android.content.Context;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.CandleEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;
/**
* @author
*/
public class MyMarkerView extends MarkerView {
private String[] data;
private DataCallback mCallback;
public MyMarkerView(Context context, int layoutResource, String[] data) {
super(context, layoutResource);
this.data = data;
}
@Override
public void refreshContent(Entry e, Highlight highlight) {
if (e instanceof CandleEntry) {
CandleEntry ce = (CandleEntry) e;
} else {
mCallback.setData(String.format("%s", data[(int) e.getX() % data.length]), String.format("%s", e.getY()), (int) e.getX() % data.length);
}
super.refreshContent(e, highlight);
}
public void setDataCallback(DataCallback dataCallback) {
this.mCallback = dataCallback;
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
public interface DataCallback {
void setData(String x, String y, int position);
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.advance.yongliu.linechartfuture.MainActivity">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="45dp"
android:gravity="center"
android:text="需求数据,滑动时展示~ ~! "
/>
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/linechart"
android:layout_width="match_parent"
android:layout_height="400dp"
/>
</LinearLayout>
开发中还会遇到一个大问题!ScrollView嵌套折线布局,横纵向滑动冲突!还好有我,这都是小问题
LineChartInViewPager(继承自LineChart的自定义控件,直接替换折线图控件就可以!LineChart布局 变为 LineChartInViewPager 布局)
package com.bakheet.garage.home.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.github.mikephil.charting.charts.LineChart;
/**
* author yongliu
* date 2018/6/6.
* desc:
*/
public class LineChartInViewPager extends LineChart {
PointF downPoint = new PointF();
public LineChartInViewPager(Context context) {
super(context);
}
public LineChartInViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineChartInViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent evt) {
switch (evt.getAction()) {
case MotionEvent.ACTION_DOWN:
downPoint.x = evt.getX();
downPoint.y = evt.getY();
break;
case MotionEvent.ACTION_MOVE:
float x = evt.getX();
float y = evt.getY();
float absX = x - downPoint.x;
float absY = y - downPoint.y;
/*if (getScaleX() > 1 && Math.abs(x - downPoint.x) > 5) {
getParent().requestDisallowInterceptTouchEvent(true);
}*/
if (Math.abs(absX)-Math.abs(absY) > 5 || Math.abs(absX) > 5) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.onTouchEvent(evt);
}
}
所遇问题
假如遇到和我项目相同的需求,需要切换不同时期的数据,这时候你会发现如果俩者之间数据差距太大,如一个数据为0、另外一个数据为10000这样的数据,共用布局的话会使布局拉扯,无法自适应! 对于这样的问题,我是通过最笨的办法处理的,也就是创建俩个折线图布局!!!
- 影藏图表周围色块
Legend legend = mLineChart.getLegend();
//默认为true,使用时设置为false
legend.setEnabled(false);
- x轴数据显示不全,如1-12月份,6等分之后,12月无法显示出来
x轴属性设置之前
xAxis.setLabelCount(6);
x轴属性设置之后,第二个参数很重要!!! 设置为true之后,12月可正常进行展示
xAxis.setLabelCount(6, true);
- x轴单条数据时无法正常展示
xAxis.setAxisMinimum(-0.5f);
- x轴N条数据时,显示N-1条数据
xAxis.setAxisMinimum(0f);
- x轴正常显示,判断x轴数据范围
if (xData.length<2){
xAxis.setAxisMinimum(-0.5f);
}else{
xAxis.setAxisMinimum(0f);
}
- x轴数据显示不全,如00:00 - 24:00,等分之后数据缺失,且部分时间段无法显示出来
/**查看是否设置上面的 setLabelCount !!!如果有的话 注释掉!
因为此控件已经帮助我们实现了等分,我们setLabelCount 只是在强制等分的数据区间!*/
//xAxis.setLabelCount(6, true); 注释此行代码 或 删掉也可以~
- 设置折线颜色、所选区域背景色、圆点色、DataSet文本颜色
//折线颜色
set.setColor(Color.parseColor("#4081D6"));
//背景色 - 填充可以设置渐变填充一个Drawable,或者仅仅填充颜色
set.setFillColor(Color.parseColor("#3F7FCD"));
//圆点色
set.setCircleColor(R.color.blue1);
//DataSet文本颜色
set.setValueTextColor(Color.parseColor("#FC4C5A"));
- 设置网格背景色
//默认是false ,如果设置true 背景会有点灰色
mLineChart.setDrawGridBackground(false);
- 设置x轴、y轴最小值(当我们的数据基本都为0时,x、y轴的数据不整齐)
//这个设置貌似是无效的,因为x轴的特殊性
xAxis.setAxisMinimum(0);
//这个设置ok的~
yAxis.setAxisMinimum(0);
- 隐藏图表文字说明,设置没数据时的文本展示
//图表周围说明文字
mLineChart.setDescription(null);
//图表没数据时的文本展示
mLineChart.setNoDataText("正在加载中,请稍后");
- 图标边框处理
//四周是否有边框 true:有 false:没有
mLineChart.setDrawBorders(false);
//边框宽度
mLineChart.setBorderWidth(0.5f);
//边框颜色,默认黑色
mLineChart.setBorderColor(Color.parseColor("#999999"));
- 横纵辅助线 (折线图的十字架,也有人叫高亮线)
//前提条件
LineDataSet set = new LineDataSet(entries, null);
/** true:显示 false:隐藏 默认为true*/
//取消纵向辅助线
set.setDrawVerticalHighlightIndicator(true);
//取消横向辅助线
set.setDrawHorizontalHighlightIndicator(true);
- 辅助线设置为 ”实线” 或者 “虚线”
//前提条件
LineDataSet set = new LineDataSet(entries, null);
/**辅助线展示形态 虚线实线得最配祸首!!!注释掉默认显示实线,
如果进行这样的配置,那么显示的就是虚线*/
set.enableDashedHighlightLine(10f, 5f, 0f);
- 辅助线、高亮线、相交线的颜色设置
//前提条件
LineDataSet set = new LineDataSet(entries, null);
//垂直线颜色,默认黑色
set.setHighLightColor(Color.parseColor("#F00000"));
- 影藏表格内的横竖线条
//一般隐藏 x轴的横线,因为它的展示形态是竖线
xAxis.setDrawGridLines(false);
//一般显示 y轴的横线,因为它的展示形态是横线
yAxis.setDrawGridLines(true);
- x轴与y轴显示方向
//控制轴上的坐标绘制在什么地方 上边下边左边右边
XAxis xAxis = mLineChart.getXAxis();
//x轴是在上边显示还是显示在下边
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//y轴显示在左侧,显示右侧的话同理
mLineChart.getAxisRight().setEnabled(false);
- 滑动设置的启动/禁止
//允许/禁止 触摸
mLineChart.setTouchEnabled(true);
// 启用/禁用拖动(平移)图表
mLineChart.setDragEnabled(true);
- 缩放、平移、双击放大的启动/禁止
//禁止x轴y轴同时进行缩放
mLineChart.setPinchZoom(false);
//启用/禁用缩放图表上的两个轴。
mLineChart.setScaleEnabled(false);
//设置为false以禁止通过在其上双击缩放图表。
mLineChart.setDoubleTapToZoomEnabled(false);
//缩放 与 setScaleEnabled意义相同
mLineChart.setScaleXEnabled(false);
mLineChart.setScaleYEnabled(false);
- 圆点相关设置
//前提条件
LineDataSet set = new LineDataSet(entries, null);
//设置是否显示圆点
set.setDrawCircles(false);
//节点不显示具体数值
set.setDrawValues(false);
//圆点的颜色
set.setCircleColor(Color.parseColor("#4081D6"));
//节点的颜色
set.setValueTextColor(Color.parseColor("#4081D6"));
- x轴数据太长导致显示不完整! 如 :2019-01-09 视图显示为2019-01-0(显示不完整)
/**设置X轴字体大小,此三方库2.2 版本后貌似就已经支持了! 设置之后数据可以显示完整,只是字有一点点小而已 - - ~*/
xAxis.setTextSize(2f);
- x轴或y轴数据太长,无法显示完全,选择 标签倾斜(UI不一定接受,那就改变展示数据的长度)
//x轴倾斜
XAxis xAxis = mLineChart.getXAxis();
xAxis.setLabelRotationAngle(45);
//y轴倾斜
YAxis yAxis = mLineChart.getYAxis();
yAxis .setLabelRotationAngle(45);
- y轴数据为0时,x轴不贴住底部
//查看是否有以下俩行代码,进行注释
//set.setAxisDependency(YAxis.AxisDependency.RIGHT);
//set.setDrawHighlightIndicators(true);
- 框架自带动画效果(部分项目会感觉动画会有卡顿感,所以用的不是很多)
mLineChart.animateX(1000, Easing.EasingOption.Linear);
mLineChart.animateY(1000, Easing.EasingOption.Linear);