ViewPager結合TabLayout --- 禁止滑動(點選切換)
【記錄】菜鳥記錄點滴
場景: ViewPager結合TabLayout,兩個Tab項(Tab1, Tab2),需要先在Tab1執行某些操作後,才能滑動ViewPager(點選Tab)切換到Tab2
1. 首先自定義CustomViewPager,可以設定允許/禁止滑動ViewPager。
繼承ViewPager,根據事件的分發機制,修改onInterceptTouchEvent()
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(canScroll){ return super.onInterceptTouchEvent(ev); } else { return false; } }
ViewPager繼承ViewGroup,禁止滑動時,canScroll = false,此時自定義的CustomViewPager不會攔截Touch事件及消費,繼續分發給子View
PS: 通過viewpager.setOnTouchListener()來消費事件,無法真正禁止滑動,此時ViewPager仍可以有小幅度的變化。
補充: 簡單查看了ViewGroup與View的dispatchTouchEvent方法,並通過Log確認,設定onTouchListener消費事件後,不會觸發onTouchEvent。再次重寫響應Scroller的computeScroll方法,ViewPager仍然會移動。
補充:ViewPager沒有重寫dispatchTouchEvent但是重寫了onInterceptTouchEvent,在重寫的onInterceptTouchEvent中,move事件是關鍵。onInterceptTouchEvent最終返回mIsBeingDragged,如果x軸上move的距離滿足條件,那麼mIsBeingDragged = true,畫面會滑動。
if (mIsBeingDragged) { // Scroll to follow the motion event if (performDrag(x)) { ViewCompat.postInvalidateOnAnimation(this); } }
至於為什麼只有第一次move會發生滑動,由於事件分發機制的很多細節理解的還不是很透徹,猜測 : dispatchTouchEvent根據target標誌決定後續處理,而第一次onInterceptTouchEvent攔截事件交給onTouchEvent消費後會標記target,此後就不會再觸發這部分邏輯。
2. 設定TabLayout不可點選切換
參照其他部落格的思路,從頭開始分析,從層次中看出需要設定TabView,再檢視原始碼。從addTab入手,發現TabView對應Tab類中的mView欄位,最終被新增到SlidingTabStrip中(design-27.1.1)。因此利用反射,獲取TabView物件,並實現禁止點選。
TabLayout.Tab tab = tabLayout.getTabAt(1);
Class clazz = tab.getClass();
try {
Field field = clazz.getDeclaredField("mView");
field.setAccessible(true);
View view = (View) field.get(tab);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(canScroll){
return false;
} else {
Log.e("lxy", "提示或者幹什麼...");
return true;
}
}
});
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
PS: 類似的,應該也可以反射獲得SlidingTabStrip,通過獲得子View來設定
補充: 按照上述的分析,實現程式碼如下,同樣可以實現
Class clazz2 = tabLayout.getClass();
try {
Field field = clazz2.getDeclaredField("mTabStrip");
field.setAccessible(true);
ViewGroup viewGroup = (ViewGroup) field.get(tabLayout);
View v = viewGroup.getChildAt(1);
v.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
ToastUtils.show("不可點選");
return true;
}
});
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}