一次性学会处理Touch事件的冲突问题(listView/tabhost/viewpager)

这几天一直在纠结这个问题。现在终于算是完满了。
先说说我都实现了什么:
1.欢迎页。
就是第一次启动才会出现的页面。用的是viewpager+SharedPreferences的方法。
2.侧滑出菜单栏。
本来是用的HorizontalScrollView来实现。可是不知怎么昨天是好的,睡了一觉出了个我解决不了的问题。后来直接用别人提供的方法。自定义类用自定义滑动。
E/HorizontalScrollView(8996): Invalid pointerId=-1 in onTouchEvent
有谁知道的求指点啊。
3.tabhost滑动切换。
4.两个tabhost的tab里面分别放入了listview和viewpager。
解决了这几个滑动操作的冲突问题。
概括起来主要就是两点:
A.怎么在父groupview的onintercepttouchevent()方法中拦截;
B.怎么在子groupview的onintercepttouchevent()方法中用getParent().requestDisallowInterceptTouchEvent(true);不允许拦截。
还有一种是重写dispatchtouchevent方法,我还不会,囧。
如果你不清楚touch事件的拦截机制,可以看看我上一篇,主要是我引用的那三篇文章。
关于android的touch事件分发,点开阅读
下面这些都是我的总结。
如果用A,请注意。第一、你当前要用来拦截的groupview能够点击的地方应该有子view,否则,down的时候找不到target,onintercepttouchevent()方法处理不到后续的动作。第二、如果拦截下来了,你还要考虑你本身是否时刻点击的,否则在ontouchEvent方法中会跳过直接返回!当然在ontouch中也是可以处理的。但是view的dispatchtouchevent方法中,ontouch方法前面还有两个判断,这是需要注意的,否则,ontouch中的代码可能会得不到执行!第三,可以发
现ontouch很像onintercepttouchevent(),都是在前面拦截,你还没执行我先看看。
如果用B,你需要把你所要保证出效果的view放在一个viewgroup中,这样,才能在onintercepttouchevent()重写中用getParent().requestDisallowInterceptTouchEvent(true);不允许拦截。这正是我用的方法。如果你要在view中直接用getParent().requestDisallowInterceptTouchEvent(true);你需要重写view的dispatchtouchevent()方法。一般来说,都是在down的时候不允许,在move的时候区分情况。
说了这么多都是空话。
下面我贴出主要的代码。
a、listview和tab的滑动切换的冲突,在只要是充满tab界面的一个viewgroup并且包含这个listview,最好直接自定义tabhost,重写onintercepttouchevent()。在move的时候判断拦截,只要拦截了代码就再也不会走到这里。只会走拦截的这个viewgroup的父类即view的dispatchtouchevent方法,如果这个viewgroup重写了view的这些方法你就必须小心,不要随意返回return super.onInterceptTouchEvent(ev);。(a标记)


        case MotionEvent.ACTION_MOVE:
            x_move = ev.getRawX();
            y_move = ev.getRawY();
moveDistanceX = (int) (x_move - x_down);
            moveDistanceY = (int) (y_move - y_down);
            // 思考,如果要区分tab1和tab2呢?
            if (tabHost.getCurrentTab() == 0) {
            //判断横向还是纵向滑动,横向不交给listview,拦截
                if (Math.abs(moveDistanceX) >= 2 * touchSlop
                        && (istabSliding || Math.abs(moveDistanceY) <= 2 * touchSlop)) {
                    istabSliding = true;
                }
                if (istabSliding) {
                //判断为滑动,拦截
                    return true;
                }
            } 

上面的一个小知识
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
这个值来自于ViewConfiguration.java,默认是8dp
它的意义是在触摸屏上操作时,当发生多大的移动时,触摸屏相应滑动或滚动的事件,
例如此值越小,相应越灵敏;此值越大,滑动时需要动作大一点,并且这个值对应的物理意义也收到触摸屏及其固件的微小影响
默认是8dp,可以在frameworks/base/core/res/res/values/config.xml里面配置
b、下面是怎么在边上划出菜单栏,自定义HorizontalScrollView
后来用其他方法写了,但此处拦截是几乎一样的

case MotionEvent.ACTION_MOVE:

            x_move = ev.getRawX();
            y_move = ev.getRawY();
            moveDistanceX = (int) (x_move - x_down);
            moveDistanceY = (int) (y_move - y_down);
            // put the calculation out of this
            //此判断是菜单显示时全部拦截,主要是菜单出来后,主界面还有一
            //部分是漏出的,但这样不好,当菜单中有内容就不行
            /*if (menu_visible) {
                Log.i(TAG, "visibale"+"intercept");
                return true;
            }*/
            // 把必须###拦截和必须不拦截###的情况写出,其余都return super.onInterceptTouchEvent(ev);
            // 即按照这个控件继承的那个控件去完成操作,这正是我们要的。
            if (!menu_visible) {
                if ((x_down < 50 || x_move < 50) && wantToScroll()) {

                     Log.i(TAG, "invisible,it is slide:" + "intercept");
                    return true;
                } else {
                    Log.i(TAG, "invisible,it is not slide:" +"no intercept");
                    // 这里必须不拦截
                    //而不能省略,因为HorizontalScrollView重写了onInterceptTouchEvent(ev)方法,
                    //返回的不是默认的false!正是爱标记出所说
                    return false;
                }
            } else {
                // 这里拦截没能右边还露出来的那一部分,
                // 当然可以直接在down拦截,但在down拦截虽然可以是吸纳
                //不滑动listview,但同时也失去了点击隐藏的效果
                if (x_down >= mMenuWidth) {
                    shouldScroll = true;
                    return true;
                }
            Log.i(TAG, "visible,it is slide:" + "intercept");
            }
break;

c、接下来是tabhost里面的viewpager,自定义了一个Fragment把viewpager包起来了。仍然是重写onInterceptTouchEvent(ev)方法。

switch (action) {
        case MotionEvent.ACTION_DOWN:// 按下
            startX = event.getX();
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        // 滑动,在此对里层viewpager的第一页和最后一页滑动做处理
        case MotionEvent.ACTION_MOVE:
            if (startX == event.getX()) {
                if (0 == child_viewpager.getCurrentItem()
                        || child_viewpager.getCurrentItem() == child_viewpager
                                .getAdapter().getCount() - 1) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
            }
            // 里层viewpager已经是最后一页,此时继续向右滑(手指从右往左滑)
            else if (startX > event.getX()) {
                if (child_viewpager.getCurrentItem() == child_viewpager
                        .getAdapter().getCount() - 1) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
            }
            // 里层viewpager已经是第一页,此时继续向左滑(手指从左往右滑)
            else if (startX < event.getX()) {
                if (child_viewpager.getCurrentItem() == 0) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
            } else {
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:// 抬起
        case MotionEvent.ACTION_CANCEL:
            getParent().requestDisallowInterceptTouchEvent(false);
            break;
        }
        return false;

好了,就这么多了。我要继续学习其他方法了。祝大家愉快。
我上传了,可以去下载
设置为1分,主要我没下载分了(一分没有。。。),请不要吝啬。。。仅一分

你可能感兴趣的:(Android学习笔记)