mpAndroidChart动态折线图的显示,支持屏幕方向切换,支持FloatDragBar随意拖动

原来是本人发在52论坛的,因为现在想在CSDN上提问,没有C币,再搬运一次吧,尴尬~!

PS:代码比较乱,因为还在忙另外一个问题,暂时不想整理了,大家将就着看吧

真机运行的时候偶有死机的情况,暂时还不清楚是啥原因

首先是Main_Activity如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/img_bg">
//参考博客[url=https://blog.csdn.net/ww897532167/article/details/77334345]https://blog.csdn.net/ww897532167/article/details/77334345[/url]
    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/lineChart"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_centerInParent="true"/>
    <com.example.cc.simplecharttest.DragFloatActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|bottom"
        android:layout_margin="16dp"
        android:src="@drawable/c_bn">
 
    </com.example.cc.simplecharttest.DragFloatActionButton>
</RelativeLayout>
package com.example.cc.simplecharttest;
 
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
 
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.LimitLine;
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.example.cc.simplecharttest.R.id.fab;
import static com.example.cc.simplecharttest.R.id.lineChart;
 
public class MainActivity extends AppCompatActivity {
   private List<String> mlist=new ArrayList<>();
   private List<Entry> entries = new ArrayList<>();
   private LineChart mLineChart;
   private LineDataSet lineDataSet;
   private LineData data;
    private int ClickTime;
    private DragFloatActionButton fab;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ClickTime=3;
        //动态加载的问题参考P113
        //FloatingActionButton fab=(FloatingActionButton)findViewById(R.id.fab );
        fab=(DragFloatActionButton)findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (ClickTime){
                    case 1:
                        ClickTime=ClickTime+1;
                        Toast.makeText(MainActivity.this,"你操死了潘雯雯1号",Toast.LENGTH_SHORT).show();
                        break;
                    case 2:
                        ClickTime=ClickTime-1;
                        Toast.makeText(MainActivity.this,"你操死了潘雯雯2号",Toast.LENGTH_SHORT).show();
                        break;
                    case 3:
                        ClickTime=ClickTime-1;
                        Toast.makeText(MainActivity.this,"你操死了潘雯雯3号",Toast.LENGTH_SHORT).show();
                        break;
                    default:
                        break;
                }
 
 
            }
        });
 
        //隐藏工具栏
        ActionBar actionBar=getSupportActionBar();
        if (actionBar!=null)
            actionBar.hide();
        //使状态栏透明
        if (Build.VERSION.SDK_INT>=21){
            View decorView=getWindow().getDecorView();
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }
        mlist.add("一月");
        mlist.add("二月");
        mlist.add("三月");
        mlist.add("四月");
        mlist.add("五月");
        mlist.add("六月");
        mlist.add("七月");
        mlist.add("八月");
        mlist.add("九月");
        mlist.add("十月");
        mlist.add("十一月");
        mlist.add("十二月");
        mlist.add("十三月");
        //实例化控件
        mLineChart=(LineChart)findViewById(lineChart);
        //显示边界
        mLineChart.setDrawBorders(true);
        //如果为True则背景不能透明,一般为False
        mLineChart.setDrawGridBackground(false);
        //获取X轴对象
        XAxis xAxis=mLineChart.getXAxis();
        //下标的位置:BOTTOM,BOTH_SIDED,BOTTOM_INSIDE,TOP,TOP_INSIDE
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
 
        //获取Y轴对象
        YAxis leftYAxis=mLineChart.getAxisLeft();
        YAxis rightYAxis=mLineChart.getAxisRight();
 
        //得到legend图例,也就是标签的意思
        Legend legend=mLineChart.getLegend();
        legend.setTextColor(Color.CYAN);
        //设置legend位置
        legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
        legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        //设置标签是否换行
        legend.setWordWrapEnabled(true);
        //隐藏标签
        //legend.setEnabled(false);
 
        //隐藏描述
        Description description=new Description();
        description.setEnabled(false);
        mLineChart.setDescription(description);
        //设置描述内容
        Description description1=new Description();
        description1.setText("X轴Description");
        description1.setTextColor(Color.RED);
        mLineChart.setDescription(description1);
 
 
        //设置Y轴值
        leftYAxis.setAxisMinimum(0f);
        leftYAxis.setAxisMaximum(100f);
        rightYAxis.setAxisMinimum(0f);
        rightYAxis.setAxisMaximum(100f);
        leftYAxis.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                return (int)value+"%";
            }
        });
        //Y轴右侧不显示
        rightYAxis.setEnabled(false);
 
        leftYAxis.setGranularity(1f);
        leftYAxis.setLabelCount(11,false);
        leftYAxis.setTextColor(Color.BLUE);//文字颜色
        leftYAxis.setGridColor(Color.RED);//网格线颜色
        leftYAxis.setAxisLineColor(Color.GREEN);//Y轴颜色
 
        //限制线LimitLine
        LimitLine limitLine1=new LimitLine(70,"上高限制性");//限制线
        limitLine1.setLineWidth(4f);//宽度
        limitLine1.setTextColor(Color.RED);
        limitLine1.setTextSize(4f);
        limitLine1.setLineColor(Color.BLUE);
        leftYAxis.addLimitLine(limitLine1);//右边Y轴添加限制线
        LimitLine limitLine2=new LimitLine(50,"下高限制性");//限制线
        limitLine2.setLineWidth(4f);//宽度
        limitLine2.setTextColor(Color.RED);
        limitLine2.setTextSize(4f);
        limitLine2.setLineColor(Color.BLUE);
        leftYAxis.addLimitLine(limitLine2);//右边Y轴添加限制线
 
 
 
        /*//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setAxisMinimum(0f);
        xAxis.setAxisMaximum(13f);*/
 
        //设置X轴下标最小间隔
        xAxis.setGranularity(1f);
        //设置X轴的刻度数量,true是按比例分配,false是适配X刻度值分配
        xAxis.setLabelCount(13,true);
 
        //设置X轴值为字符串,一次一月到12月
        xAxis.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                return mlist.get((int)value);
            }
        });
 
    //定义数组,设置数据
        //List<Entry> entries = new ArrayList<>();
    for (int i = 0; i < 13; i++)
        //产生10个点并赋值,相当于第一个是横轴坐标值,第二个是竖轴坐标值
        entries.add(new Entry(i, (float) (Math.random()) * 80));
    //曲线数据集
    lineDataSet = new LineDataSet(entries, "温度");
 
    //取消曲线显示的值为整数与设置自定义X轴类似。设置曲线显示值为整数,可在设置曲线LineDataSet 时,修改值的类型
        /*lineDataSet.setValueFormatter(new IValueFormatter() {
            @Override
            public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
                int IValue=(int)value;
                return String.valueOf(IValue);
            }
        });*/
 
    //LineChart的数据源
    data = new LineData(lineDataSet);
    //chart装入数据
    mLineChart.setData(data);
        //视图更新,没有这一步,曲线不会呈现动态
        //mLineChart.invalidate();
        //点击弹框
    MyMarkerView mv = new MyMarkerView(MainActivity.this);
    mLineChart.setMarker(mv);//有失效方法
    mLineChart.setTouchEnabled(false);
 
        //启动服务
        /*Intent intent=new Intent(this,MyService.class);
        startService(intent);*/
 
        /*Entry entry = new Entry(lineDataSet.getEntryCount(), number);
        lineData.addEntry(entry, 0);
        //通知数据已经改变
        lineData.notifyDataChanged();
        mLineChart.notifyDataSetChanged();
        //设置在曲线图中显示的最大数量
        mLineChart.setVisibleXRangeMaximum(10);
        //移到某个位置
        mLineChart.moveViewToX(lineData.getEntryCount() - 5);*/
        new MyThread().start();
 
    }
 
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        /*重置floatActionBar位置否则容易找不到
        fab.setX(100);
        fab.setY(100);*/
        if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
            Toast.makeText(this,"当前屏幕为竖屏会影响效果,建议横屏观看",Toast.LENGTH_SHORT).show();
        super.onConfigurationChanged(newConfig);
    }
 
    class MyThread extends Thread{
        @Override
        public void run() {
            while (true){try {
                Thread.sleep(2000);
 
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //逻辑
                    //定义数组,设置数据
                    entries.clear();
                    mLineChart.clear();
                    for (int i = 0; i < 13; i++)
                        //产生10个点并赋值,相当于第一个是横轴坐标值,第二个是竖轴坐标值
                        entries.add(new Entry(i, (float) (Math.random()) * 80));
                    //曲线数据集
                    lineDataSet = new LineDataSet(entries, "温度");
                    data = new LineData(lineDataSet);
                    //通知数据已经改变
                    mLineChart.setData(data);
 
 
                }
            });
        }
        }
    }
}
//参考网站[url=https://blog.csdn.net/ww897532167/article/details/74139843]https://blog.csdn.net/ww897532167/article/details/74139843[/url]

下面关键代码,测量屏幕的大小,以便可以随意拖动DragBarTool

package com.example.cc.simplecharttest;
 
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
 
import java.lang.reflect.Method;
 
/**
 * Created by cc on 2018/6/9.
 */
 
public class ScreenUtils {
    private ScreenUtils(){
        //不让被实例化??
        throw new UnsupportedOperationException("cannot be instantiated");
    }
    //获取屏幕宽度
    public static int getScreenWidth(Context context){
        //获取实例
        WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        //不包括下方虚拟按键
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
 
        return outMetrics.widthPixels;
    }
    //获取屏幕宽度
    public static int getScreenHeight(Context context){
        //获取实例
        WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        //不包括下方虚拟按键
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }
    //获取状态栏的高度
    public static int getStatusHeight(Context context){
        int statusHeight=-1;
        try{
            //获取类,反射方法
            Class<?> clazz=Class.forName("com.android.internal.R$dimen");
            //实例化类
            Object object=clazz.newInstance();
            int height=Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
            statusHeight=context.getResources().getDimensionPixelSize(height);
        }catch (Exception e)
        {e.printStackTrace();}
        return statusHeight;
    }
    //获取虚拟功能键高度
    public static int getVirtualBarHeigh(Context context) {
        //虚拟功能键的高
        int vh = 0;
        //虚拟功能键的宽
        int vw=0;
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        //获取屏幕信息
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics dm = new DisplayMetrics();
        try {
            //反射
            @SuppressWarnings("rawtypes")
            Class c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            //getRealMetrics(display, dm)
            method.invoke(display, dm);
            //vh = dm.heightPixels - windowManager.getDefaultDisplay().getHeight();//有替代方法,下面三行就是
            windowManager.getDefaultDisplay().getMetrics(dm);
            vh=dm.heightPixels;
            vw=dm.widthPixels;
 
 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return vh;
    }
    //获取标题栏高度
 
    public static int getVirtualBarHeigh(Activity activity) {
        int titleHeight = 0;
        Rect frame = new Rect();
        //getDecorView()的意思是当前窗口的根View
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        //标题高度
        int statusHeight = frame.top;
        //Window.ID_ANDROID_CONTENT表示视图的内容部分
        titleHeight = activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop() - statusHeight;
        //返回标题的高度
        return titleHeight;
    }
}

下面是注册拖动控件

package com.example.cc.simplecharttest;
 
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.BounceInterpolator;
 
/**
 * Created by cc on 2018/6/9.
 */
 
public class DragFloatActionButton extends FloatingActionButton {
    private int screenWidth;
    private int screenHeight;
    private int screenWidthHalf;
    private int statusHeight;
    private int virtualHeight;
    private int lastX;
    private int lastY;
    private boolean isDrag;
    public DragFloatActionButton(Context context){
        super(context);
        init();
    }
    public DragFloatActionButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    private void init(){
        screenWidth = ScreenUtils.getScreenWidth(getContext());
        screenWidthHalf = screenWidth / 2;
        screenHeight = ScreenUtils.getScreenHeight(getContext());
        statusHeight = ScreenUtils.getStatusHeight(getContext());
        virtualHeight=ScreenUtils.getVirtualBarHeigh(getContext());
 
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int rawX = (int) ev.getRawX();
        int rawY = (int) ev.getRawY();
        //处理多点触摸事件
        switch (ev.getAction()&MotionEvent.ACTION_MASK){
            case MotionEvent.ACTION_DOWN:
                isDrag=false;
                //取得焦点,可以接受事件,当传入的参数为true时,表示子组件要自己消费这次事件,告诉父组件不要拦截(抢走)这次的事件
                //对于底层的View来说,有一种方法可以阻止父层的View截获touch事件,就是调用getParent().requestDisallowInterceptTouchEvent(true);方法。一旦底层View收到touch的action后调用这个方法那么父层View就不会再调用onInterceptTouchEvent了,也无法截获以后的action。
                getParent().requestDisallowInterceptTouchEvent(true);
                lastX = rawX;
                lastY = rawY;
                break;
            case MotionEvent.ACTION_MOVE:
                isDrag = true;
                //计算手指移动了多少
                int dx = rawX - lastX;
                int dy = rawY - lastY;
                //这里修复一些手机无法触发点击事件的问题
                int distance= (int) Math.sqrt(dx*dx+dy*dy);
                if(distance<3){//给个容错范围,不然有部分手机还是无法点击
                    isDrag=false;
                    break;
                }
 
                float x = getX() + dx;
                float y = getY() + dy;
                //检测是否到达边缘 左上右下
                x = x < 0 ? 0 : x > screenWidth - getWidth() ? screenWidth - getWidth() : x;
                Log.d("move---->", "屏幕宽度screenwidth"+screenWidth+"getwidth宽度"+getWidth()+"屏幕高度screenheight"+screenHeight);
                //y = y < statusHeight ? statusHeight : (y + getHeight() >= screenHeight ? screenHeight - getHeight() : y);
                if (y<0){
                    y=0;
                }
                //getHeight()本身的高度
                if (y>screenHeight-getHeight()){
                    y=screenHeight-getHeight();
                }
                setX(x);
                setY(y);
 
                lastX = rawX;
                lastY = rawY;
                Log.e("move---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf + " " + isDrag+"  statusHeight="+statusHeight+ " virtualHeight"+virtualHeight+ " screenHeight"+ screenHeight+"  getHeight="+getHeight()+" y"+y);
                break;
            //在UP里添加吸附功能
            case MotionEvent.ACTION_UP:
                if (isDrag) {
                    //恢复按压效果
                    setPressed(false);
                    Log.e("ACTION_UP---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
                    if (rawX >= screenWidthHalf) {
                        //设置动画效果,设置动画为减速动画(动画播放中越来越慢)向左吸附
                        animate().setInterpolator(new BounceInterpolator())
                                .setDuration(155)//设置动画时间
                                .xBy(screenWidth - getWidth() - getX())//啥意思?不懂
                                .start();
                    } else {
                        //动画Float型平滑过渡(向右吸附)
                        ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);//“x”是啥意思不懂
                        oa.setInterpolator(new BounceInterpolator());
                        oa.setDuration(155);//设置动画时间
                        oa.start();
                    }
                }
                Log.e("up---->",isDrag+"");
                break;
        }
        return isDrag ||super.onTouchEvent(ev);
    }
}

build.gradle代码

apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 26
    buildToolsVersion "27.0.0"
    defaultConfig {
        applicationId "com.example.cc.simplecharttest"
        minSdkVersion 23
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
 
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
    compile 'com.android.support:design:26+'
    testCompile 'junit:junit:4.12'
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值