【干货】多图表交互联动的通用简单方法(MPAndroidChart为例)

本文致力于解决三张及其以上的图表如何简单实现复杂联动不侵入,非MPAndroidChart框架同样适用!

不多bb先放demo 内容非常简单,免费资源,这次就不收分了 哈哈

https://download.csdn.net/download/qq_28844947/89291613

效果图

标题

核心方法

对于图表如K线指标等经常需要多图联动(高亮联动,缩放联动,平移联动,手势跨图表等),常用的框架一般只会单个功能或者两个图表联动一旦多了就十分复杂,今天以MPAndroidChart为例,原框架提供了如下方法,是指定一种监听的回调 彼此传值3个图表就非常麻烦了。A-B A-C B-A B-C C-A C-B 如果去自定义一些ontouch绑定对框架修改也大,非常坑,如果我们做股票交易所之类 4图表岂不是麻烦死了吗

   chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {

            }

            @Override
            public void onNothingSelected() {

            }
        });

那么有没有一种巧妙的方法呢?

那么我们可以换个思路,既然单个图表的功能都是没有问题的,我们只需要把当前被选中图表的事件,直接发给其他图表即可,然后判断被选中的图表是哪个作为区分,功能即可实现,也不用修改原代码,核心代码超简单,用一个层盖在所有view上面

咱们一步一步看

1.先给一个view盖住所有chart,挡住所有事件

2.将本应该一个图表的事件,通过盖住的view,发给所有图表
        findViewById(R.id.flMainTouch).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                for (int i = 0; i < charts.length; i++) {
                    LineChart mChart = charts[i];

                    // 事件普通传递
                    mChart.onTouchEvent(event);

                }


                return true;
            }
        });
3.查看此时效果 可以看到虽然Y值是假的,不适用,导致markview消失,但是X是准的,已经让高亮线线满足需要

4.你如果想进一步判断具体是哪个图表,加单markview,其他图表则只显示X轴 增加判断isTouchPointInView,即把真正的图表被touch的送入准确Y,其他图表去掉横线

效果如图 常用多图表十字线单markview,此时已经基本满足需求

  //父布局统一控制集体分发,那么N图高亮联动和缩放等复杂问题则一切解决了,只需要如下微调
        flMainTouch.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                for (int i = 0; i < mCharts.length; i++) {
                    LineChart mChart = mCharts[i];

                    //1.事件普通传递
                    mChart.onTouchEvent(event);


                    int x = (int) event.getRawX();
                    int y = (int) event.getRawY();
                    boolean touchPointInView = isTouchPointInView(mCharts[i], new Point(x, y));
                    LineDataSet lineDataSet = ((LineDataSet) mChart.getLineData().getDataSetByIndex(0));
                    if (touchPointInView) {
                        lineDataSet.setDrawHorizontalHighlightIndicator(true);
                        if (currI != i) {
                            Log.i("rex", "当前触摸点在第" + (i + 1) + "张图上面");
                            currI = i;
                        }
                        mChart.setMarker(new MyMarkerView(LineChartActivityColored.this, R.layout.custom_marker_view));
                    } else {
                        // 去掉非命中图表横线
                        lineDataSet.setDrawHorizontalHighlightIndicator(false);
                        mChart.setMarker(null);
                    }
                }


                return true;
            }
        });

判断在哪个图表上面

 // 判断一个具体的触摸点是否在 view 上;
    public static boolean isTouchPointInView(View view, Point point) {
        if (view == null && point == null) {
            throw new NullPointerException();
        }
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        int left = location[0];
        int top = location[1];
        int right = left + view.getMeasuredWidth();
        int bottom = top + view.getMeasuredHeight();
        if (point.x >= left && point.x <= right && point.y >= top && point.y <= bottom) {
            return true;
        }
        return false;
    }

5.继续进阶,假设你的图表还有其他缩放等更复杂的需求

则可以使用下面的ChartsControllerOnTouchUtils,你能做出这样的需求 下面的utils使用自然也不是难事,所以demo中不包含第5项的使用

1.如果图表上还有其他按钮则也得一起绑定才行

2.如果你的需求还有自定义onTouch事件如 高亮线不限制于线上平滑移动啊,那么有个坑等着你

MPAndroidChart源码中onTouchEvent被覆盖了,所以你自定义的事件必须继承ChartTouchListener

3.然而“ChartTouchListener”是个空方法 你得去继承它的实现类(例如BarLineChartTouchListener)才能保留图表本身的一些功能如超屏滑动

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        if (mChartTouchListener == null || mData == null)
            return false;

        // check if touch gestures are enabled
        if (!mTouchEnabled)
            return false;
        else
            return mChartTouchListener.onTouch(this, event);
    }

    public boolean onTouchEventParent(MotionEvent event) {
        return super.onTouchEvent(event);

    }
/**
 * Created by Rex on 2018/11/17.
 * 集中分发多个图表的事件
 */
public class ChartsControllerOnTouchUtils {
    private static int currI;

    public static void bindWithExpand(final View flMainTouch, final View expandView, final CombinedChart... mCharts) {
        //父布局统一控制集体分发,那么N图高亮联动和缩放等复杂问题则一切解决了,只需要如下微调
        flMainTouch.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                Point touchPoint = new Point(x, y);

                if (isTouchPointInView(expandView, touchPoint)) {
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        expandView.performClick();
                    }
                    return true;
                }
                dispatchToChart(flMainTouch, event, mCharts);
                return true;
            }
        });
    }


    public static void bind(final View flMainTouch, final CombinedChart... mCharts) {
        //父布局统一控制集体分发,那么N图高亮联动和缩放等复杂问题则一切解决了,只需要如下微调
        flMainTouch.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                dispatchToChart(flMainTouch, event, mCharts);
                return true;
            }
        });
    }

    public static void dispatchToChart(final View flMainTouch, MotionEvent event, final CombinedChart... mCharts) {
        for (int i = 0; i < mCharts.length; i++) {
            CombinedChart mChart = mCharts[i];

            //1.事件普通传递
            mChart.onTouchEvent(event);
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            boolean touchPointInView = isTouchPointInView(mCharts[i], new Point(x, y));

            LineScatterCandleRadarDataSet dataNotBarSet = null;
            BarLineScatterCandleBubbleDataSet barDataSet = null;

            if (mChart.getLineData() != null) {
                dataNotBarSet = (LineScatterCandleRadarDataSet) mChart.getLineData().getDataSetByIndex(0);
            } else if (mChart.getScatterData() != null) {
                dataNotBarSet = (LineScatterCandleRadarDataSet) mChart.getScatterData().getDataSetByIndex(0);
            } else if (mChart.getCandleData() != null) {
                dataNotBarSet = (LineScatterCandleRadarDataSet) mChart.getCandleData().getDataSetByIndex(0);
            } else if (mChart.getCombinedData() != null) {
//                        VolBarDataSet cannot be cast to com.github.mikephil.charting.data.LineScatterCandleRadarDataSet
//                        BarDataSet barDataSet ;BarLineScatterCandleBubbleDataSet
                IBarLineScatterCandleBubbleDataSet<? extends Entry> combinedDataSet = mChart.getCombinedData().getDataSetByIndex(0);
                if (combinedDataSet instanceof LineScatterCandleRadarDataSet) {
                    dataNotBarSet = (LineScatterCandleRadarDataSet) combinedDataSet;
                } else {
                    barDataSet = (BarLineScatterCandleBubbleDataSet) combinedDataSet;
                }
            } else if (mChart.getBarData() != null) {
                barDataSet = (BarLineScatterCandleBubbleDataSet) mChart.getBarData().getDataSetByIndex(0);
            } else {
                Log.i("rex", "高亮数据异常" + mChart.toString());
                continue;
            }

            if (dataNotBarSet != null) {
                dataNotBarSet.setHighlightEnabled(true);
                if (SettingsUtil.Companion.isNightTheme()) {
                    dataNotBarSet.setHighLightColor(Color.parseColor("#C0C3CB"));
                } else {
                    dataNotBarSet.setHighLightColor(Color.parseColor("#0F3457"));
                }
            }
            if (barDataSet != null) {
                barDataSet.setHighlightEnabled(true);
                if (SettingsUtil.Companion.isNightTheme()) {
                    barDataSet.setHighLightColor(Color.parseColor("#C0C3CB"));
                } else {
                    barDataSet.setHighLightColor(Color.parseColor("#0F3457"));
                }
            }

            if (touchPointInView) {
                //此处控制高亮线
                if (dataNotBarSet != null) {
                    dataNotBarSet.setDrawHorizontalHighlightIndicator(true);
                }
                if (barDataSet != null) {
                    barDataSet.setHighlightEnabled(true);
                }

                if (currI != i) {
                    Log.i("rex", "当前触摸点在第" + (i + 1) + "张图上面");
                    currI = i;
                }
                //此处添加marker
//                mChart.setMarker(new LeftMarkView(flMainTouch.getContext()));
            } else

            {
                if (dataNotBarSet != null) {
                    dataNotBarSet.setDrawHorizontalHighlightIndicator(false);
                }
//                if (barDataSet != null) {
//                    barDataSet.setHighlightEnabled(false);
//                }
                mChart.setMarker(null);
            }
        }

    }

    // 判断一个具体的触摸点是否在 view 上;
    public static boolean isTouchPointInView(View view, Point point) {
        if (view == null && point == null) {
            throw new NullPointerException();
        }
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        int left = location[0];
        int top = location[1];
        int right = left + view.getMeasuredWidth();
        int bottom = top + view.getMeasuredHeight();
        if (point.x >= left && point.x <= right && point.y >= top && point.y <= bottom) {
            return true;
        }
        return false;
    }
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
好的,很高兴为您解答这个问题。 在深度学习中,数据增强是一种常用的技术,它可以通过对原始数据进行变换、裁剪、旋转、翻转等操作,来扩充训练集,从而提高模型的泛化能力和鲁棒性。在图像领域,常用的数据增强方法包括随机裁剪、随机旋转、随机翻转、色域变换等。下面,我将为您介绍如何使用 Python 对图像进行随机数据增强。 1. 随机裁剪 随机裁剪是一种简单而有效的数据增强方法,它可以通过对原始图像进行随机裁剪,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机裁剪。 ```python from PIL import Image import random def random_crop(img, crop_size): w, h = img.size left = random.randint(0, w - crop_size) top = random.randint(0, h - crop_size) right = left + crop_size bottom = top + crop_size return img.crop((left, top, right, bottom)) ``` 2. 随机旋转 随机旋转是一种常用的数据增强方法,它可以通过对原始图像进行随机旋转,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机旋转。 ```python from PIL import Image import random def random_rotate(img, angle_range): angle = random.uniform(-angle_range, angle_range) return img.rotate(angle) ``` 3. 随机翻转 随机翻转是一种简单而有效的数据增强方法,它可以通过对原始图像进行随机翻转,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现随机翻转。 ```python from PIL import Image import random def random_flip(img, flip_prob): if random.random() < flip_prob: return img.transpose(Image.FLIP_LEFT_RIGHT) return img ``` 4. 色域变换 色域变换是一种常用的数据增强方法,它可以通过对原始图像进行色彩变换,来扩充训练集。在 Python 中,我们可以使用 PIL 库中的 Image 模块来实现色域变换。 ```python from PIL import Image import random def random_color(img, color_range): r, g, b = img.split() r = r.point(lambda i: i + random.randint(-color_range, color_range)) g = g.point(lambda i: i + random.randint(-color_range, color_range)) b = b.point(lambda i: i + random.randint(-color_range, color_range)) return Image.merge('RGB', (r, g, b)) ``` 以上就是使用 Python 进行随机数据增强的一些常用方法,希望对您有所帮助。如果您有任何问题,请随时联系我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值