Android 處理滑動衝突的攔截方法(事件分發)
一.外部攔截
屬於事件分發的正常套路,需要攔截就攔截,不需要就不攔截
@Override public boolean onInterceptTouchEvent(MotionEvent event){ boolean intercepted = false; int x = (int) event.getX(); int y = (int) event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_UP: intercepted = false; break; case MotionEvent.ACTION_MOVE: if(父佈局需要滑動) intercepted = true; else intercepted = false; break; default: break; } mLastX = x; mLastY = y; return intercepted; }
二.內部攔截
逆向的,控制父view不攔截事件,然後子view根據情況控制父view去攔截
分析
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } } else { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true; }
解讀1:mFirstTouchTarget != null 當父view將事件傳遞給子view處理時,此條件成立。
由此可見第一個if判斷中,事件不由子view處理以及事件為move或者up事件時,將不會走判斷,直接攔截事件,也因此攔截了down事件後其他事件也都交由其處理。
解讀2:FLAG_DISALLOW_INTERCEPT標示位,用於子view控制父view的攔截情況使用(通過對requestDisallowInterceptTouchEvent的設定,控制邏輯是否走進判斷中,通過對父view的onInterceptTouchEvent方法的重寫,進而控制父view是否攔截事件)
具體思路:
down事件下來後為了父view不攔截事件,在子view中down事件呼叫getParent().requestDisallowInterceptTouchEvent(true)使得父View不會攔截其他move、up事件。然後子view會根據自己的實際情況調getParent().requestDisallowInterceptTouchEvent(false)讓父view走進判斷中,因為重寫了父view的onInterceptTouchEvent方法,當為非down事件的時候進行攔截。
實現如下:
父View:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { return false;//不攔截down事件 } else { return true;//攔截除down事件之外的其他事件 } }
子View
@Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: if(某種條件){ getParent().requestDisallowInterceptTouchEvent(false); } break; case MotionEvent.ACTION_UP: break; default: break; } //這裡不能返回false return super.dispatchTouchEvent(ev); }
喵印~~