巧解ViewPager滑动冲突

       在Android开发过程中,你一定会用到ViewPager这个控件,最让人头疼的就是各种滑动冲突,比如说:在ListView,SrollView中嵌套ViewPager,在作侧边栏滑动时和ViewPager的冲突,甚至还有ViewPager嵌套ViewPager的情况等等,解决起来很麻烦,今天和大家分享一下我心得。这些冲突无非就是横向滑动和纵向滑动的一个冲,而我们要解决的就是要判断将事件给父控件还是子控件处理。

       先看代码:

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
/**
 * @Package com.ml.news.ui.view
 * @ClassName: ChildViewPager
 * @Description: 解决viewpager内嵌viewpager滑动冲突问题
 * @author malong
 * @date Mar 26, 2015 8:56:24 PM
 */
public class ChildViewPager extends ViewPager {

    public ChildViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ChildViewPager(Context context) {
        super(context);
    }

    // 滑动距离及坐标 归还父控件焦点
    private float xDistance, yDistance, xLast, yLast,mLeft;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d("touch", "ACTION_DOWN");
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                mLeft = ev.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
                xLast = curX;
                yLast = curY;
                if (mLeft<100||xDistance < yDistance) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                } else {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}
核心代码就是 getParent().requestDisallowInterceptTouchEvent(false);这句;当为false则通知父view可以拦截touch事件,由父view处理,而当为true时,则会 阻止父层的View截获touch事件,这样就会返回个子view处理。那么好,解决了这个关键性问题接下来的问题,就是要解决什么时候交给子view或是父view的问题了。当ScrollView和ListView中嵌套ViewPager的时候,多数是在作轮播的幻灯片,冲突无非就是能左右滑动,不能上下滑动的问题;而ViewPager内嵌套ViewPager这是子view不能滑动,一划就是父ViewPager滑动的问题;这两个问题上面的自定义ViewPager都能解决,解决思路是在事件分发down的时候记录xLast和yLast,然后在move的时候比较xDistance和yDistance即x轴差和y轴差,如果x轴差小于y轴差,则说明是上下滑动,此时将事件还给父view,反之左右滑动把事件交给子view,Ok问题解决了。

        细心的朋友可能会问,那mLeft是干嘛用的阿?是这样的,可能我在项目中会用道侧边栏,我的用的是SlidingMenuLibrary这个开源组件,可以设置将侧边栏划出的区域,这时就会跟ViewPager冲突,都是左右滑,事件被子view吃掉了,侧边栏画不出来,所以我就加个mLeft当点击屏幕左侧边缘(即down时x<100)时,将事件还给父view这样既不影响侧边栏划出,也不影响ViewPager的滑动。同样你可以举一反三,灵活控制事件响应区域。

        再给大家说一个扩展的,如果用过ViewPagerIndicatorLibrary朋友,可能会遇到,ViewPager内套ViewPager,这时我们就想能不能在内部ViewPager滑到最后一页时,父ViewPager在切换到下一页,提供一个思路:就是在事件分发时判断当前页是不是第一页或最后一页,如果是最后一页且向左滑将事件交给父view即可,以此类推。

        增强版如下:万能解决方案

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

/**
 * @Package com.ml.news.ui.view
 * @ClassName: ChildViewPager
 * @Description: 解决viewpager内嵌viewpager滑动冲突问题
 * @author malong
 * @date Mar 26, 2015 8:56:24 PM
 */
public class ChildViewPager extends ViewPager {

    public ChildViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ChildViewPager(Context context) {
        super(context);
    }

    // 滑动距离及坐标 归还父控件焦点
    private float xDistance, yDistance, xLast, yLast,xDown, mLeft;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(true);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d("touch", "ACTION_DOWN");
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                xDown = ev.getX();
                mLeft = ev.getX();// 解决与侧边栏滑动冲突
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
                xLast = curX;
                yLast = curY;
                if (mLeft < 100 || xDistance < yDistance) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                } else {
                    if (getCurrentItem() == 0) {
                        if (curX < xDown) {
                            getParent().requestDisallowInterceptTouchEvent(true);
                        } else {
                            getParent().requestDisallowInterceptTouchEvent(false);
                        }
                    } else if (getCurrentItem() == (getAdapter().getCount()-1)) {
                        if (curX > xDown) {
                            getParent().requestDisallowInterceptTouchEvent(true);
                        } else {
                            getParent().requestDisallowInterceptTouchEvent(false);
                        }
                    } else {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}


你可能感兴趣的:(android)