HorizontalScrollView实现右滑菜单与ListView左滑删除冲突解决(事件分发顺序)

欢迎指正错误O(∩_∩)O!
首先解决这件事需要了解android的事件分发机制,和事件分发的顺序,如何计算view的坐标。

计算坐标

假设已掌握 ~(≧▽≦)/~

事件分发机制

假设已掌握 ~(≧▽≦)/~

事件分发顺序

点击或滑动事件摊派到了某个view(设为v),v如何知道这个事件它能否处理?答案是通过view的几个事件响应方法得知,这几个事件相应方法分别是onTouch、onTouchEvent、onLongClick、onClick(可能还有,这里只列举这几个)。
onTouch:每个view都可以设置滑动监听器,只要实现onTouchLintener接口即可。
onTouchEvent:view的滑动事件响应方法,如果view没有实现onTouch接口,就由这个方法处理滑动事件,处理成功返回true,没有处理返回false,返回true则事件不再下发。
onLongClick:长按屏幕的响应方法,如果上面的方法返回true,这个方法就不会被执行。
onClick:同上,区别在于这个是点击事件,不是长按。
方法的执行顺序已给出,onTouch->onTouchEvent->onLongClick->onClick。这里有一个小坑,点击事件(带Click的)没有返回值,怎么知道事件是否被消费? 查看源码发现他们两的返回值其他方法隐藏了,其实他们是有返回值的。
代码为证:

        relativeLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("onClick","relativeLayout");
                Toast.makeText(MainActivity.this, "ajuergeirgbesrbglehasrbe",Toast.LENGTH_SHORT).show();
            }
        });
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("onClick","textView");
                Toast.makeText(MainActivity.this, "asdfgwerg",Toast.LENGTH_SHORT).show();
            }
        });

代码中的textView是定义在relativeLayout中的,经测试证明Log.e(“onClick”,”relativeLayout”);这句话没有被输出。

滑动冲突解决

首先说明情况,我用继承HorizontalScrollView的方式实现了滑动菜单,右滑就会出现,同时主布局上的ListView也实现了滑动删除,这两个分开用都是好使的,但是合在一起,ListView的滑动就失灵了。
开始我怀疑滑动事件在HorizontalScrollView的层次上就被截住了,没有下发,但事实证明没有被截住,ListView的dispatchTouchEvent与onTouchEvent方法都正常响应了,但却只响应了DOWN动作,偶尔响应一两次MOVE动作,这让我非常蛋痛=。=
然后,我想到了一个改进办法,强行下发,就是从HorizontalScrollView层次直接下发到ListView上,跳过中间的所有view,像这样:

public class SlidingMenu extends HorizontalScrollView{
........
    public boolean dispatchTouchEvent(MotionEvent event){
        Log.e(LOG, " dispatchTouchEvent");
        if(isOpen == false){
            int downX;
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    Log.e(LOG, " DOWN");
                    downX = (int)event.getX();
                    if(downX > mScreenWidth/6){
                        slideList.dispatchTouchEvent(event);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.e(LOG, " MOVE");
                    downX = (int)event.getX();
                    if(downX > mScreenWidth/6){
                        slideList.dispatchTouchEvent(event);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    Log.e(LOG, " UP");
                    downX = (int)event.getX();
                    if(downX > mScreenWidth/6){
                        slideList.dispatchTouchEvent(event);
                    }
                    break;
            }
        }
        return super.dispatchTouchEvent(event);
    }
........
}

结果光荣的空指针了,被强制结束。经查证是event的坐标无法定位到ListView上面:

            case MotionEvent.ACTION_DOWN:
                downX = (int) ev.getX();
                downY = (int) ev.getY();
                Log.e("SlideList", "X :" + downX + " Y :" + downY);
                currentPosition = pointToPosition(downX, downY);

                }

这是自写的listview中dispatchTouchEvent方法的其中一段,ev即从SlidingMenu传过来的event,错误在于通过ev的坐标计算不出listview的position,也就不知道是哪个item该滑动。
再然后,我发现

                downX = (int) ev.getX();
                downY = (int) ev.getY();

这样写获得的是滑动事件起点相对于父view原点的坐标,对于我的程序来说,就是应用程序原点(区别应用程序原点和屏幕原点的位置,两者不相等,Y轴上差了50,标题栏占25还有一个什么占25,所以应用程序原点应该是(0,50))。
小贴士:相对坐标 = ((x1-x2),(y1-y2)),即(x1,y1)相对于(x2,y2)的坐标。
pointToPosition这个方法可以计算坐标计算出点击位置在listview的哪个item上,但它只接受相对于listview的坐标,而ev的坐标确实相对于应用程序原点的,所以出错。
分析明白了,解决办法也就出现了,一道非常简单的数学题。只需要获取滑动事件对于屏幕原点的坐标:

                downX = (int) ev.getRawX()
                downY = (int) ev.getRawY()

同时获取listview对于屏幕原点的坐标:

        int[] local = new int[2];
        this.getLocationOnScreen(local);
        //  local[0] 即 X   local 即 Y

他们两相减就OK了:

                downX = (int) ev.getRawX() - local[0];
                downY = (int) ev.getRawY() - local[1];

到此,问题解决,listview的滑动正常了。
但我又发现两个新问题,listview刷新卡顿与滑动判断不严谨(纵向滑动时横向滑动也再判断)。革命尚未成功同志仍需努力=。=

猜你喜欢

转载自blog.csdn.net/nvnnv/article/details/51510172