ListView onTouchEvent 快速滑動丟失 ACTION_DOWN事件

最近在工做中,遇到須要自定義Listview Item的左右滑動效果,ListView Item自己有點擊事件,滑動過程當中item須要顯示不一樣於其餘的背景顏色,滑開以後,背景顏色保持而且又有item內的點擊事件這樣:java

說明這個問題呢,須要先說明一下這個效果的實現邏輯:app

一、根據ACTION_DOWN事件的按下位置,獲取ListView被按下位置的item,並設置按下背景顏色ide

二、根據ACTION_MOVE時間判斷滑動距離,若是滑動達到左右滑動閾值,那麼根據左右滑動距離,將View進行左右位置偏移,若是未達到閾值則不處理該事件。this

三、用戶可點擊整個item,觸發跳轉事件spa

四、View位置移動後,用戶點擊Delete按鈕,刪除該條itemrest

五、若是View已經被用戶移開,那麼若是再次觸發ACTION_DOWN,被移開的View自動恢復到原來位置。code

主要邏輯如上,效果實現不難,重寫ListView的onTouch事件就行了啊,可是在自測過程當中,發現一個大問題,就是在快速滑動ListView的時候,onTouch方法有事會丟失ACTION_DOWN事件。可是後面的Move事件和up事件歷來沒有丟失過。若是都丟失還好,可是MOVE和UP沒有丟失,就致使關鍵判斷丟失,又加上ListView item的複用機制,致使整個ListView狀態出錯,搞地整我的都很差了。事件

覺得是我本身寫的方法哪裏返回值有錯,就將全部本身的寫的東西註釋掉,而後在onTouchEvent裏面打印DOWN的狀態,發現就是沒有我代碼,DOWN事件同樣在快速滑動的時候接收不到。不是本身代碼的問題就好。而後Google了好幾下,發現問這個問題的很多,可是能解決個人問題方案沒有。就在我覺得這是一個不可解決的問題的時候,我驚恐的發現,QQ的item就不存在這個問題,每次劃開,再快的速度滑動,均可以正常關閉,我擦擦,不能輸啊。get

因而開始看源碼,細節就很少說,結論以下:源碼

該DOWN事件在ListView 的dispatchTouchEvent的時候是能夠接收到的,可是在onTouchEvent方法裏面就接收不到了。因此咱們就去看看ListView的dispatchTouchEvent方法,ListView的dispatchTouchEvent是在ViewGroup裏面,只看通過我分析關鍵的部分:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            // Handle an initial down.
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }

            // Check for interception.
            final boolean intercepted;
            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;
            }
            .
            .
            .
    }
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;
                }

關鍵就在這裏,咱們能夠看到有一句:// restore action in case it was changed,由於快速滑動,當DOWN事件傳遞到onInterceptTouchEvent方法去判斷是否是該攔截的時候,MOVE事件來了,而後被restore了。

因而在onInterceptTouchEvent方法裏面打印了一下是否有丟失DOWN事件,發現是:木有丟失!!!好噠,問題就在這裏了。瞭解問題在這裏,這個問題就容易解決了。重寫onInterceptTouchEvent,判斷DOWN事件的位置是否是須要攔截,返回正確的TRUE or FALSE值就OK了嘍。

相關文章
相關標籤/搜索