Android---SwipeRefreshLayout巢狀ViewPager時的滑動衝突
阿新 • • 發佈:2018-12-14
SwipeRefreshLayout巢狀ViewPager
最近在專案中用到了SwipeRefreshLayout控制元件,以實現下拉重新整理,在我的SwipeRefreshLayout佈局中存在一個ViewPager。那麼問題就出現了,當我對ViewPager進行左右滑動時,只要你的滑動手勢有偏下,即往左下或者右下滑動時,會觸發SwipeRefreshLayout的下拉動作,導致不能正常對ViewPager進行滑動操作。
解決方法
對於Android的事件分發機制在這篇文章裡就不再贅述,之後有時間再寫篇文章針對事件分發進行闡述吧。那對於本文描述的這種情況,其實思路很簡單,即對使用者的滑動手勢進行判斷,下拉事件就交給SwipeRefreshLayout處理,左右滑動事件SwipeRefreshLayout就不進行攔截,直接下發到ViewPager進行處理。那怎麼區分下拉還是左右滑動呢,我用到的一個思路就是根據使用者移動手勢的X方向位移dx和Y方向位移dy進行判斷,如果dx>dy,那麼就認為是左右滑動,交給ViewPager,如果dy>dx,就認為是上下滑動,交給SwipeRefreshLayout並攔截(看原始碼你會發現SwipeRefreshLayout是繼承ViewGroup的,對事件進行攔截後就不會再下發到子View,具體流程在此不贅述)。
程式碼示例
下面的程式碼是我重寫的一個SwipeRefreshLayout,對使用者滑動手勢進行了判斷處理:
public class SunnySwipeRefreshLayout extends SwipeRefreshLayout { private float startX; private float startY; private boolean mIsXMove;// 是否橫向拖拽 private final int mTouchSlop;// getScaledTouchSlop()得來的一個距離,表示滑動的時候,手勢移動要大於這個距離才開始移動控制元件,ViewPager就是用這個距離來判斷使用者是否翻頁 public SunnySwipeRefreshLayout (Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mIsXMove = false; startX = ev.getX(); startY = ev.getY(); break; case MotionEvent.ACTION_MOVE: // 如果橫向移動則不攔截,直接return false; if (mIsXMove) { return false; } float endX = ev.getX(); float endY = ev.getY(); float distanceX = Math.abs(endX - startX); float distanceY = Math.abs(endY - startY); // 如果dx>xy,則認定為左右滑動,將事件交給viewPager處理,return false if (distanceX > mTouchSlop && distanceX > distanceY) { mIsXMove= true; return false; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mIsXMove= false; break; } // 如果dy>dx,則認定為下拉事件,交給swipeRefreshLayout處理並攔截 return super.onInterceptTouchEvent(ev); } }
這麼處理之後,在這個下拉重新整理佈局中再巢狀ViewPager或是其他存在左後滑動操作的控制元件時,就不會再產生這種滑動衝突啦。 大家如果有更好的方案歡迎留言討論~