Android可拖拽控件的实现,同时解决和onClick事件的冲突问题

在项目中用到了可拖拽控件,在网上看了几篇相关的文章,发现有的方案存在瑕疵,于是进行了简单的修改,看代码

 

private int lastX = 0;
private int lastY = 0; //手指在屏幕上的坐标

private boolean isDraged = false; //View是否被移动过
private boolean isDrag = false; //判断是拖动还是点击
private class DragViewOnTouchListener implements OnTouchListener{

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        int parentRight = ((ViewGroup)v.getParent()).getWidth();
        int parentBottom = ((ViewGroup)v.getParent()).getHeight();
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                isDrag = false;
                isDraged = false;
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = (int) event.getRawX()-lastX;
                int dy = (int) event.getRawY()-lastY; //手指在屏幕上移动的距离

                if (isDraged){
                    isDrag = true; //如果已经被拖动过,那么无论本次移动的距离是否为零,都判定本次事件为拖动事件
                }else{
                    if (dx == 0 && dy == 0){
                        isDraged = false; //如果移动的距离为零,则认为控件没有被拖动过,灵敏度可以自己控制
                    }else{
                        isDraged = true;
                        isDrag = true;
                    }
                }

                int l = v.getLeft()+dx;
                int b = v.getBottom()+dy;
                int r = v.getRight()+dx;
                int t = v.getTop()+dy;
                if(l < 0){//处理按钮被移动到父布局的上下左右四个边缘时的情况,防止控件被拖出父布局
                    l = 0;
                    r = l + v.getWidth();
                }
                if(t < 0){
                    t = 0;
                    b = t + v.getHeight();
                }
                if(r > parentRight){
                    r = parentRight;
                    l = r - v.getWidth();
                }
                if(b > parentBottom){
                    b = parentBottom;
                    t = b - v.getHeight();
                }
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                v.layout(l, t, r, b);
                v.postInvalidate(); //其他view刷新时,会导致view回到原点,可以用设置LayoutParams的方式代替
                break;
        }
        return isDrag; //如果没有给view设置点击事件,需返回true,否则不会响应ACTION_MOVE,导致view不会被拖动
    }
}

思路很简单,实现OnTouchListener,在move过程中重绘view。但是如果onTouch方法返回true,就会消费掉本次事件,导致即使是点击事件,onClick事件也不再响应,如果返回false,那么在对控件进行拖动的同时,也会响应onClick事件,所以我们需要一个标志位,就是代码中的isDrag。

 

private boolean isDrag = false; //判断是拖动还是点击

 

但是在实现过程中,发现了另外一个问题,如果只是点击,onTouch中的ACTION_MOVE也会触发,导致onClick事件不响应,所以我们需要另外一个标志位,isDraged。

 

private boolean isDraged = false; //View是否被移动过

 

下面这段代码为判断逻辑

 

                if (isDraged){
                    isDrag = true; //如果已经被拖动过,那么无论本次移动的距离是否为零,都判定本次事件为拖动事件
                }else{
                    if (dx == 0 && dy == 0){
                        isDraged = false; //如果移动的距离为零,则认为控件没有被拖动过,灵敏度可以自己控制
                    }else{
                        isDraged = true;
                        isDrag = true;
                    }
                }

如果拖动过,那么则认为本次事件为拖动事件,不需要再判断移动距离(移动距离为0时,也会触发ACTION_MOVE),也就是说,从按下到抬起,中间的过程如果有拖动,那么之后都不再根据move的距离来判定是不是拖动事件。

相反,如果从按下之后到本次ACTION_MOVE事件触发之前,还没有拖动过,那么再根据move的距离进行判断。

这么做主要是为了应对两种情况:

1,就是上边提到的,单纯的点击事件也会触发ACTION_MOVE

2,拖动控件后不动,触发ACTION_MOVE之后,移动距离为零

 

最后,onTouch方法,再将是否是拖动事件的标志位,也就是isDrag返回就可以了。

 

另外,说一下下边这个方法

 

                v.layout(l, t, r, b);

该方法是指在父布局中的位置,也就是说

 

v.layout(0,0,v.getWidth(),v.getBottom());

会布局到父布局的左上角,所以,想要不被拖出父布局,那么四个参数的取值范围如下

left : 0 到 parent.getWidth() - v.getWidth()

top : 0 到 parent.getHeight() - v.getHeight()

right : v.getWidth() 到 parent.getWidth()

bootom : v.getHeight() 到 parent.getHeight()

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值