------因爲種種緣由,本文廢話較多,代碼較少,可根據需求斷定是否須要深刻閱讀。html
ScrollView裏面放了具有橫向滑動的東西,進度條啊、橫向的列表啊、banner等ide
ScrollView裏面放好幾層的LIstView、RecyclerView(其實很是不推薦這樣作)佈局
各類縱向橫向的帶滑動的東西交叉使用spa
滑動、拖動的權限原本是你們都有的,把它私有化就行了,具體的私有化過程就是不給ScrollView滑動,不給LIstView下滑,不給Seekbar拖動,差很少就是這個意思。code
再詳細一點,就是吧具體的相關的某些控件的onTouchEven事件給屏蔽了,核心在這個方法:
requestDisallowInterceptTouchEvent()htm
onTouchEven這個方法還有兩個小夥伴須要瞭解一下(dispatchTouchEvent、OnInterceptTouchEven),他們之間的故事仍是挺精彩的,也很少介紹,能夠去看下別人的博客,這裏有個鏈接:https://www.cnblogs.com/neil-zhao/p/3778094.htmlblog
其實大概意思就是,dispatchTouchEvent是有限執行,且用requestDisallowInterceptTouchEvent是不能屏蔽掉的,onTouchEven則是這些可拖動可下滑的控件滑動的關鍵,因此只要吧父容器的onTouchEven屏蔽掉的話,就能達到橫向滑動的時候禁止縱向滑動的效果。事件
須要作的就是重寫控件的onTouchEven方法,在按下的時候或者是滑動超出某個範圍的時候禁止列表下滑,能夠看下簡單的代碼:get
/** * 設置須要屏蔽觸摸事件的控件(橫向移動幅度大於60像素的時候會促發屏蔽效果) * @param view */ public void stopTouchShield(final View view){ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { // 記錄點擊到ViewPager時候,手指的X座標 lastX = event.getX(); } if (action == MotionEvent.ACTION_MOVE) { float x=event.getX()-lastX; if(x<0){ x*=-1; } if(x>4f){ recyclerView.requestDisallowInterceptTouchEvent(true); } } if (action == MotionEvent.ACTION_UP) { // 用戶擡起手指,恢復父佈局狀態 recyclerView.requestDisallowInterceptTouchEvent(false); } return false; } }); }
我用了不少下拉刷新的組件,不少用的都不太舒服,滑動回彈的效果不是我喜歡的,因此本身手擼了一個下拉刷新的,還有一個ScrollView,寫這兩個東西的時候,若是是重寫控件的onTouchEven方法的時候,老是會出現莫名其妙的拖不動或者是回彈出錯的毛病,因此重寫的時候基本上不懂onTouchEven方法,而是改成重寫dispatchTouchEvent,而後就一路順風了。源碼
沒有去深刻研究Android的源碼,有個研究過的大神在一篇博客裏面說過,若是requestDisallowInterceptTouchEvent不生效的話,就是跟dispatchTouchEvent有關係,dispatchTouchEvent在搞某種操做的時候會把requestDisallowInterceptTouchEvent設置的參數重置,大概是這個意思,具體描述我也找不到那篇博客了,反正能夠肯定的是,若是requestDisallowInterceptTouchEvent不生效,那就是跟dispatchTouchEvent有關係。
經過我手擼下拉刷新的經驗,能夠重寫ScrollView、RecyclerView等控件的dispatchTouchEvent方法,在須要屏蔽掉下滑操做的時候,屏蔽掉super.dispatchTouchEvent操做,而後再結合requestDisallowInterceptTouchEvent來使用,應該沒問題。
我這裏的寫法就是,重寫的時候提供屏蔽的方法,而後多加一個boolean變量用於標識是否須要屏蔽掉dispatchTouchEvent,而後在重寫的dispatchTouchEvent的時候加上這個boolean變量斷定是否須要執行後續的操做。
習慣性貼一下代碼,不保證適用:
@Override public boolean dispatchTouchEvent(MotionEvent event) { if(!isTouchShield){ //不屏蔽滑動事件 return super.dispatchTouchEvent(event); } } /** * 設置須要屏蔽觸摸事件的控件(橫向移動幅度大於60像素的時候會促發屏蔽效果) * @param view */ public void stopTouchShield(final View view){ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { // 記錄點擊到ViewPager時候,手指的X座標 lastX = event.getX(); } if (action == MotionEvent.ACTION_MOVE) { float x=event.getX()-lastX; if(x<0){ x*=-1; } if(x>4f){ recyclerView.requestDisallowInterceptTouchEvent(true); isTouchShield(true); } } if (action == MotionEvent.ACTION_UP) { // 用戶擡起手指,恢復父佈局狀態 recyclerView.requestDisallowInterceptTouchEvent(false); isTouchShield(false); } return false; } }); }