【干货】多图表交互联动的通用简单方法(MPAndroidChart为例)
目录
效果图
核心方法
注意事项(如果你需求复杂一定得看)
联系交流
效果图
核心方法
对于图表如K线指标等经常需要多图联动(高亮联动,缩放联动,平移联动,手势跨图表等),常用的框架一般只会单个功能或者两个图表联动一旦多了就十分复杂,今天以MPAndroidChart为例,原框架提供了如下方法 彼此传值3个图表就非常麻烦了。如果去自定义一些ontouch绑定对框架修改也大,非常坑
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { @Override public void onValueSelected(Entry e, Highlight h) { } @Override public void onNothingSelected() { } });
那么我们可以换个思路,既然单个图表的功能都是没有问题的,我们只需要把当前被选中图表的事件,直接发给其他图表即可,然后判断被选中的图表是哪个作为区分,功能即可实现,也不用修改原代码,核心代码超简单,用一个层盖在所有view上面
//父布局统一控制集体分发,那么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 = top && point.y <= bottom) { return true; } return false; }
注意事项(如果你需求复杂一定得看)
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 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 = top && point.y <= bottom) { return true; } return false; }}
联系交流
如果还需要实际能跑起来的demo项目请评论区留言 q501127630