Android进阶之路 - 快速实现经营报表折线图

之前有那么一段时间比较 “凉~”

以下一段内容是在下 - 微微的抱怨,可跳过~

因为项目需求 ,需要一个折线图的经营报表 ,所以我找到了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);
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远方那座山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值