众所周知,viewPager是可以滑动的,但有时候咱们须要禁止它的滑动(微笑地面对*—……—*)。android
状况是这样的:ide
activity中有一个viewPager,viewPager中加入3个Fragment,第三个Fragment中又使用了一个viewPager,这个viewPager中又加入了几个Fragment(本人不是受虐狂,仅仅是功能须要)。如图:this
想实现的功能:spa
点击activity的图标或者滑动的时候可以切换第一个viewPager中的Fragment,点击Fragment3中的图标可以切换第二个viewPager里的Fragment,可是禁止这个viewPager滑动,第二个viewPager里的Fragment1里面有一个listView(有下拉刷新功能),要可以上下滑动不受影响。3d
关键就是禁止内部viewPager滑动,可是其它的功能不受影响。code
呵呵,已经元气大伤......blog
探索过程已经不想吐槽。事件
这个问题涉及到事件的分发机制,须要重写viewPager。那么到底该重写哪一个viewPager呢?get
首先分析一下这个问题的解决过程:it
1.要禁止里面的viewPager左右滑动,那么便是说当咱们左右滑动的时候,外面的viewPager要拦截事件,当咱们上下滑动的时候外面的viewPager不能拦截事件,这样事件才能传递到内部的viewPager,内部viewPager里的fragment包含的listView才能上下滑动。
2.固然点击事件也不可以拦截,这样点击Fragment3的图标才能切换内部viewPager里面的Fragment。
3.因为内部viewPager在Fragment3,因此咱们在外部的viewPager切换到item3的时候再作1,2步的处理。
在这里重写外部viewPager会比较方便,即咱们用外部拦截法。
接下来请看外部拦截神功。
import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import neo.door.usermanager.UserManager; public class MyViewPager extends ViewPager { private int mFirstX =0,mFirstY=0; private String TAG = "MyViewPager"; public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if(this.getCurrentItem()==2) //若是滑动到了第三个Fragment { boolean isIntercept=false; int x=(int) event.getX(); int y=(int) event.getY(); Log.e(TAG, "onInterceptTouchEvent"); switch (event.getAction()) {
/**
* 父容器必须返回false,即不拦截ACTION_DOWN事件,
* 不然后续的ACTION_MOVE,ACTION_UP事件都会直接交给父容器处理,
* 事件没办法再传递给子元素了
*/ case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onInterceptTouchEvent_ACTION_DOWN"); isIntercept=false;
break;
/**
* 根据须要觉定是否拦截
*/ case MotionEvent.ACTION_MOVE: if (Math.abs(x - mFirstX) > Math.abs(y - mFirstY)) //左右滑动 { isIntercept = true; if(正在下拉) //想刷新时候(若不写这一步,若是咱们向下滑到一半忽然左右滑动那么listView就会卡在中间状态不动。) isIntercept=false; } else //上下滑动 { isIntercept = false; } Log.e(TAG, "onInterceptTouchEvent_ACTION_MOVE"); break;
/**
* 必须返回false,由于ACTION_UP自己没有太大意义。
*
*/ case MotionEvent.ACTION_UP: isIntercept=false; Log.e(TAG, "onInterceptTouchEvent_ACTION_UP"); break; default: break; } mFirstX=x; mFirstY=y; Log.e(TAG, "onInterceptTouchEvent_return"); return isIntercept; } else //若是没有滑动到了第三个Fragment,不做处理 return super.onInterceptTouchEvent(event); } }
首先要知道 onInterceptTouchEvent这个方法,返回true表明拦截,返回false表明不拦截。
注意:
1.ACTION_UP。
考虑一种状况:如果事件交给子元素处理,而父容器在ACTION_UP的时候返回了true,那么子元素就会没法收到ACTION_UP事件,子元素的onClik事件没法触发,也就是说在这道题中,Fragment3的图标将没法点击,而且listView的滑动会在手指离开屏幕的时候停留在中间态。
父容器比较特殊,一旦它开始拦截任何一个事件,那么后续事件都会交给它处理,ACTION_UP做为最后一个事件也同样能够传递给父容器,即使父容器的onInterceptTouchEvent方法在ACTION_UP时返回了false。
2.ACTION_MOVE之中。
假如咱们要刷新listView,在咱们下拉listView的时候手指忽然间左滑或者右滑,那么listView就会停留在中间状态。放开手也不会回去,为何呢?
缘由是这样的:在咱们手指下滑的时候,在ACTION_MOVE中判断后不符合 (Math.abs(x - mFirstX) > Math.abs(y - mFirstY)),因此父容器即外部的viewPager返回false,不拦截事件,listView可以滑动。可是当咱们在下滑的时候忽然间左右滑,那么在ACTION_MOVE中判断后符合 (Math.abs(x - mFirstX) > Math.abs(y - mFirstY)),因此父容器即外部的viewPager返回true,拦截了事件,因此listView没法完成事件,只是停留在了手指左右滑动以前的那个瞬间状态。(这种状况最后的ACTION_UP没有执行,这点还不理解)
因此咱们要加个判断,判断listview是否正要下拉刷新,若是是,不要拦截事件。
至于判断方法挺多的,就再也不写。
【写到这里,也就差很少了,之后如果有得补充再来补充吧。@—^—@】