MPAndroidChart MarkerView的精确点击问题解决方案

说到在Android中画图,相信大家对MPAndroidChart不陌生,其功能强大,能画出各种各样非常绚丽的效果图。但是近期公司的项目要求在markerview上添加一些按钮,能够直接在markerview上操作按钮来直接对图上的point进行操控。然后在lib里找了半天,发现原生根本就不支持此功能,然后在其github MPAndroidChart的issue里查找相关问题,发现还真是有很多人提出了这个问题,让作者解决这个问题,但是这个问题一直没有得到很好的解决,记得作者在issue里回答说”it is harder than what I thought…”,然后就没有然后了。我直接懵逼…

但是,硬着头皮也要上,自己override各种方法来尝试,均为成功,差点没有崩溃!最后,在issue里发现了一个对我很有启发的方式,这里谢谢这个哥们儿!
https://github.com/PhilJay/MPAndroidChart/issues/2482

不过这种方式需要改源码,不能让你使用如下方式来集成进项目
compile ‘com.github.PhilJay:MPAndroidChart:v3.0.0-beta1’
所以,要解决这个问题,首先必须把MPAndroidChart从github上download下来,以compile library的方式来使用。

另外,这个只解决了,是否点击了markerview,如果点击了的话,相应其点击事件。如果此时,需要更为精确的控制,比如最开始提出的在markerview里添加一些按钮,对这些按钮来响应不同的点击事件,该怎么办呢?我这里已经实现了!在这里把它分享出来,相信对有需要的朋友有所帮助!

  1. 在BarLineChartBase里修改一下onTouchEvent方法,如下:
@Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

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

        //这里是新添加的判断,让markerView有机会相应点击事件!
        if(mMarker !=null && MotionEvent.ACTION_UP == event.getAction() && mMarker.isTouch(event)){
            mMarker.markViewClick();
            return true;
        }

        // check if touch gestures are enabled
        if (!mTouchEnabled)
            return false;
        else
            return mChartTouchListener.onTouch(this, event);
    }
  1. 在IMarker里添加如下方法
boolean isTouch(MotionEvent event);
void markViewClick();
  1. 在MarkerView里修改draw方法,实现isTouch,markViewClick方法,另外添加2个属性用来记录点击point在markerview里的相对位置
/**
     * relativeTouchPointX, relativeTouchPointY 是 touch 的点相对于 markerView 的 left, top 的坐标
     */
    private float relativeTouchPointX = 0;
    private float relativeTouchPointY = 0;

    public float getRelativeTouchPointX() {
        return relativeTouchPointX;
    }

    public void setRelativeTouchPointX(float relativeTouchPointX) {
        this.relativeTouchPointX = relativeTouchPointX;
    }

    public float getRelativeTouchPointY() {
        return relativeTouchPointY;
    }

    public void setRelativeTouchPointY(float relativeTouchPointY) {
        this.relativeTouchPointY = relativeTouchPointY;
    }
......

/**
     *
     * @param canvas
     * @param posX 画图的point X值
     * @param posY 画图的point Y值
     */
    @Override
    public void draw(Canvas canvas, float posX, float posY) {

        MPPointF offset = getOffsetForDrawingAtPoint(posX, posY);

        int saveId = canvas.save();
        // translate to the correct position and draw
        canvas.translate(posX + offset.x, posY + offset.y);
        draw(canvas);
        canvas.restoreToCount(saveId);

        mpPointF.x = posX;
        mpPointF.y = posY;
    }

    @Override
    public boolean isTouch(MotionEvent event) {
        if(mpPointF.x == 0)
            return false;

        float left = mpPointF.x - getWidth() / 2;
        float top = mpPointF.y - getHeight();
        float right = mpPointF.x + getWidth() / 2;
        float bottom = mpPointF.y;

        boolean touchInMarkerView = new RectF(left, top, right, bottom).contains(event.getX(), event.getY());

        if(touchInMarkerView){
            setRelativeTouchPointX(event.getX() - left);
            setRelativeTouchPointY(event.getY() - top);
        }

        mpPointF.x = 0;
        mpPointF.y = 0;

        return touchInMarkerView;
    }

    @Override
    public void markViewClick() {
    }
  1. 在自己的markerview实现类里,得到不同按钮的在markerview的相对位置,override getOffset方法,最后就可以override markViewClick方法,在里面精确的控制点击区域,来控制不同的点击事件了!
public class DemoMarkerView  extends MarkerView{
    private Context context;
    private TextView tv;
    private Button minusBtn;
    private Button addBtn;
    private float minusBtnLeft, minusBtnTop, minusBtnRight, minusBtnBottom;
    private float addBtnLeft, addBtnTop, addBtnRight, addBtnBottom;

    public DemoMarkerView(Context context, int layoutResource) {
        super(context, layoutResource);
        this.context = context;
        tv = (TextView) findViewById(R.id.tv);
        minusBtn = (Button) findViewById(R.id.minus);
        addBtn = (Button) findViewById(R.id.add);
    }

    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        super.refreshContent(e, highlight);
        tv.setText("x = " + e.getX() + ", y = " + e.getY());

        minusBtnLeft = minusBtn.getLeft();
        minusBtnTop = minusBtn.getTop();
        minusBtnRight = minusBtn.getRight();
        minusBtnBottom = minusBtn.getBottom();

        addBtnLeft = addBtn.getLeft();
        addBtnTop = addBtn.getTop();
        addBtnRight = addBtn.getRight();
        addBtnBottom = addBtn.getBottom();

        Log.e("Demo", "minusBtn: left = " + minusBtn.getLeft() + ", top = " + minusBtn.getTop() + ", right = " + minusBtn.getRight() + ", bottom = " + minusBtn.getBottom());
    }

    @Override
    public MPPointF getOffset() {
        MPPointF mpPointF = new MPPointF();
        mpPointF.x = - getWidth() / 2;
        mpPointF.y = - getHeight();

        return mpPointF;
    }

    @Override
    public void markViewClick() {
        Log.e("Demo", "onClick relativeTouchPointX = " + getRelativeTouchPointX() + ", relativeTouchPointY = " + getRelativeTouchPointY());

        float x = getRelativeTouchPointX();
        float y = getRelativeTouchPointY();
/**
*   最终的核心思想就是利用点击point在markerview中的相对位置,是否被包含在了对应的button区域内。因为此时button的(l,t,r,b)也是相对于markerviwe的坐标,这样2者在同一个坐标系中,是可以判断的。从而实现了点击不同的区域,就相当于点击不同的按钮事件!
**/
        if(new RectF(minusBtnLeft, minusBtnTop, minusBtnRight, minusBtnBottom).contains(x, y))
            Toast.makeText(context, "onClick minusButton!", Toast.LENGTH_SHORT).show();
        else if(new RectF(addBtnLeft, addBtnTop, addBtnRight, addBtnBottom).contains(x, y))
            Toast.makeText(context, "onClick addButton!", Toast.LENGTH_SHORT).show();
        else
            Toast.makeText(context, "onClick markerView!", Toast.LENGTH_SHORT).show();
    }
}

其中,markerview的layout.xml内容如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@color/colorPrimary"
    android:orientation="vertical"
    android:layout_width="150dp"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/tv"
        android:textColor="@android:color/white"
        android:textSize="16sp"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/minus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="-"/>
    <Button
        android:id="@+id/add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="+"/>
</LinearLayout>

很简单,只有一个textview,和2个按钮,点击minus和add按钮toast不同的内容。

大家可以直接去github上下载我给出的demo:
https://github.com/AndrewXiao/MarkerViewClickDemo

如果还有什么不清楚的,欢迎留言!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值