MPAndroidChart之折线图详情使用(X轴文本换行,滑动,限制线)

简介: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 布局中使用

   <!--心率-->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:layout_marginRight="20dp"
                android:layout_marginTop="20dp"
                android:text="心率"/>

            <com.github.mikephil.charting.charts.LineChart
                android:id="@+id/linCart"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"/>
            <!--呼吸率-->
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="right"
                android:layout_marginRight="20dp"
                android:layout_marginTop="20dp"
                android:text="呼吸率"/>

            <com.github.mikephil.charting.charts.LineChart
                android:id="@+id/linCartBreath"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"/>

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<Entry> values = new ArrayList<Entry>();
        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<String> mTimeList;

        public StringAxisValueFormatter(List<String> 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<String> mYaxitData;

        public AxisValueFormatter(List<String> 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<Entry> 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<ILineDataSet> mDataSets = new ArrayList<ILineDataSet>();
            //添加数据集
            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轴坐标换行,具体属性 源码里面没提供接口出来,需要自己重写方法去实现,水平滑动,只要设置一下最大值和最小值就行,但是同时你要设置下 支持触摸,不然会没效果的,好了 今天就分享到这里,有问题欢迎随时留言。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值