眾所周知,viewPager是能夠滑動的,但有時候我們需要禁止它的滑動(微笑地面對*—……—*)。 情況是這樣的: activity中有一個viewPager,viewPager中加入3個Fragment,第三個Fragment中又使用了一個viewPager,這個viewPager中又加入了幾個F ...
眾所周知,viewPager是能夠滑動的,但有時候我們需要禁止它的滑動(微笑地面對*—……—*)。
情況是這樣的:
activity中有一個viewPager,viewPager中加入3個Fragment,第三個Fragment中又使用了一個viewPager,這個viewPager中又加入了幾個Fragment(本人不是受虐狂,僅僅是功能需要)。如圖:
想實現的功能:
點擊activity的圖標或者滑動的時候能夠切換第一個viewPager中的Fragment,點擊Fragment3中的圖標能夠切換第二個viewPager里的Fragment,但是禁止這個viewPager滑動,第二個viewPager里的Fragment1裡面有一個listView(有下拉刷新功能),要能夠上下滑動不受影響。
關鍵就是禁止內部viewPager滑動,但是其它的功能不受影響。
呵呵,已經元氣大傷......
探索過程已經不想吐槽。
這個問題涉及到事件的分發機制,需要重寫viewPager。那麼到底該重寫哪個viewPager呢?
首先分析一下這個問題的解決過程:
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是否正要下拉刷新,如果是,不要攔截事件。
至於判斷方法挺多的,就不再寫。
【寫到這裡,也就差不多了,以後若是有得補充再來補充吧。@—^—@】