使用MPAndroidChart实现K线图(5)——高亮联动、横竖屏切换

目录

使用MPAndroidChart实现K线图(1)——基本用法

使用MPAndroidChart实现K线图(2)——自定义XY轴

使用MPAndroidChart实现K线图(3)——自定义柱状图

使用MPAndroidChart实现K线图(4)——图表联动、加载更多

使用MPAndroidChart实现K线图(5)——高亮联动、横竖屏切换


由于前面画出的K线图已经默认实现了左右手势滑动图表,此时再滑动高亮的话,会造成冲突。因此把高亮的逻辑设置成只有长按才可以触发高亮,高亮时,其他手势无效,此时高亮跟随手指滑动,手势结束时高亮结束;未触发高亮时仅执行默认逻辑。由于Chart的手势监听器OnChartGestureListener只会触发部分手势效果,且滞后于View的OnTouchListener,因此需要自定义监听器ChartFingerTouchListener,继承View.OnTouchListener。

public class ChartFingerTouchListener implements View.OnTouchListener {

    private BarLineChartBase mChart;
    private GestureDetector mDetector;
    private HighlightListener mListener;
    private boolean mIsLongPress = false;

    public ChartFingerTouchListener(BarLineChartBase chart, HighlightListener listener) {
        mChart = chart;
        mListener = listener;
        mDetector = new GestureDetector(mChart.getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
                mIsLongPress = true;
                if (mListener != null) {
                    mListener.enableHighlight();
                }
                Highlight h = mChart.getHighlightByTouchPoint(e.getX(), e.getY());
                if (h != null) {
                    h.setDraw(e.getX(), e.getY());
                    mChart.highlightValue(h, true);
                    mChart.disableScroll();
                }
            }
        });
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mDetector.onTouchEvent(event);
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            mIsLongPress = false;
            mChart.highlightValue(null, true);
            if (mListener != null) {
                mListener.disableHighlight();
            }
            mChart.enableScroll();
        }
        if (mIsLongPress && event.getAction() == MotionEvent.ACTION_MOVE) {
            if (mListener != null) {
                mListener.enableHighlight();
            }
            Highlight h = mChart.getHighlightByTouchPoint(event.getX(), event.getY());
            if (h != null) {
                h.setDraw(event.getX(), event.getY());
                mChart.highlightValue(h, true);
                mChart.disableScroll();
            }
            return true;
        }
        return false;
    }

    public interface HighlightListener {
        void enableHighlight();
        void disableHighlight();
    }
}

其中,设置回调接口HighlightListener,当高亮有效和关闭高亮时回调到外部。高亮线跟随手指滑动,需要在绘制高亮线之前把手指接触点的坐标保存下来,高亮对象Highlight已经使用元素mX、mY、mXPx、mYPx保存了高亮点的坐标(蜡烛图的高亮点为接触蜡烛的中心点),不方便直接改动,而其中还有不太重要的元素mDrawX、mDrawY,使用其setDraw(float x, float y)方法,可以用来保存接触点的坐标。

由于ChartFingerTouchListener仅处理一个图表(称为图A)的手势交互,并触发高亮,此时还需要在图A有高亮变化时,主动去通知相关联的图表(称为图B)去处理相应的高亮。因此需要自定义高亮监听器CoupleChartValueSelectedListener,继承OnChartValueSelectedListener。

public class CoupleChartValueSelectedListener implements OnChartValueSelectedListener {

    private BarLineChartBase srcChart;
    private BarLineChartBase[] dstCharts;
    private ValueSelectedListener mListener;

    public CoupleChartValueSelectedListener(BarLineChartBase srcChart, BarLineChartBase... dstCharts) {
        this(null, srcChart, dstCharts);
    }

    public CoupleChartValueSelectedListener(ValueSelectedListener mListener,
                                            BarLineChartBase srcChart, BarLineChartBase... dstCharts) {
        this.mListener = mListener;
        this.srcChart = srcChart;
        this.dstCharts = dstCharts;
    }

    @Override
    public void onValueSelected(Entry e, Highlight h) {
        if (dstCharts != null) {
            for (BarLineChartBase chart : dstCharts) {
                float touchY = h.getDrawY();//手指接触点在srcChart上的Y坐标,即手势监听器中保存数据
                float y = h.getY();
                if (chart instanceof BarChart) {
                    y = touchY - srcChart.getHeight();
                } else if (chart instanceof CombinedChart) {
                    y = touchY + chart.getHeight();
                }
                Highlight hl = new Highlight(h.getX(), Float.NaN, h.getDataSetIndex());
                hl.setDraw(h.getX(), y);
                chart.highlightValues(new Highlight[]{hl});
            }
        }
        if (mListener != null) {
            mListener.valueSelected(e);
        }
    }

    @Override
    public void onNothingSelected() {
        if (dstCharts != null) {
            for (BarLineChartBase chart : dstCharts) {
                chart.highlightValues(null);
            }
        }
        if (mListener != null) {
            mListener.nothingSelected();
        }
    }

    public interface ValueSelectedListener {
        void valueSelected(Entry e);
        void nothingSelected();
    }
}

关于手指接触点的Y坐标,在图表范围内,从上边缘到下边缘,从0开始依次递增,最大为图表的高度;在图表以外的上面区域,其值为负,越往上越小;在图表以外的下面区域,从图表下边缘开始,越往下越大。对于同一个点,它在图A和在图B中的Y坐标是不同的(图A和图B不重叠),因此图A通知图B高亮时,需要计算接触点在图B中的坐标,然后再使图B高亮。我们这里的K线图,CombinedChart和BarChart是上下相连且无间隙的,如果长按触发高亮的点在CombinedChart中,接触点在CombinedChart中的Y坐标减去CombinedChart的高度,即为接触点在BarChart中的Y坐标;如果触发高亮的点在BarChart中,接触点在BarChart中的Y坐标加上CombinedChart的高度,即为接触点在CombinedChart中的Y坐标。另外,新建Highlight时把y值设置为Float.NaN可保证Highlight不出现异常(绘制高亮时并不使用其y值)。

把监听器设置给CombinedChart和BarChart,并实现其接口中的方法。

        //初始化方法中设置
        cc.setOnChartValueSelectedListener(new CoupleChartValueSelectedListener(this, cc, bc));//高亮联动监听
        bc.setOnChartValueSelectedListener(new CoupleChartValueSelectedListener(this, bc, cc));
        cc.setOnTouchListener(new ChartFingerTouchListener(cc, this));//手指长按滑动高亮
        bc.setOnTouchListener(new ChartFingerTouchListener(bc, this));

    @Override
    public void valueSelected(Entry e) {
        //
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值