衆所周知,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是否正要下拉刷新,若是是,不要攔截事件。
至於判斷方法挺多的,就再也不寫。
【寫到這裏,也就差很少了,之後如果有得補充再來補充吧。@—^—@】