ListView onTouchEvent 快速滑動(dòng)丟失 ACTION_DOWN事件

最近在工作中,遇到需要自定義Listview Item的左右滑動(dòng)效果,ListView Item本身有點(diǎn)擊事件,滑動(dòng)過(guò)程中item需要顯示不同于其他的背景顏色,滑開(kāi)之后,背景顏色保持并且又有item內(nèi)的點(diǎn)擊事件這樣:



說(shuō)明這個(gè)問(wèn)題呢,需要先說(shuō)明一下這個(gè)效果的實(shí)現(xiàn)邏輯:
1、根據(jù)ACTION_DOWN事件的按下位置,獲取ListView被按下位置的item,并設(shè)置按下背景顏色
2、根據(jù)ACTION_MOVE時(shí)間判斷滑動(dòng)距離,如果滑動(dòng)達(dá)到左右滑動(dòng)閾值,那么根據(jù)左右滑動(dòng)距離,將View進(jìn)行左右位置偏移,如果未達(dá)到閾值則不處理該事件。
3、用戶可點(diǎn)擊整個(gè)item,觸發(fā)跳轉(zhuǎn)事件
4、View位置移動(dòng)后,用戶點(diǎn)擊Delete按鈕,刪除該條item
5、如果View已經(jīng)被用戶移開(kāi),那么如果再次觸發(fā)ACTION_DOWN,被移開(kāi)的View自動(dòng)恢復(fù)到原來(lái)位置。
主要邏輯如上,效果實(shí)現(xiàn)不難,重寫(xiě)ListView的onTouch事件就好了啊,但是在自測(cè)過(guò)程中,發(fā)現(xiàn)一個(gè)大問(wèn)題,就是在快速滑動(dòng)ListView的時(shí)候,onTouch方法有事會(huì)丟失ACTION_DOWN事件。但是后面的Move事件和up事件從來(lái)沒(méi)有丟失過(guò)。如果都丟失還好,但是MOVE和UP沒(méi)有丟失,就導(dǎo)致關(guān)鍵判斷丟失,又加上ListView item的復(fù)用機(jī)制,導(dǎo)致整個(gè)ListView狀態(tài)出錯(cuò),搞地整個(gè)人都不好了。
以為是我自己寫(xiě)的方法哪里返回值有錯(cuò),就將所有自己的寫(xiě)的東西注釋掉,然后在onTouchEvent里面打印DOWN的狀態(tài),發(fā)現(xiàn)就是沒(méi)有我代碼,DOWN事件一樣在快速滑動(dòng)的時(shí)候接收不到。不是自己代碼的問(wèn)題就好。然后Google了好幾下,發(fā)現(xiàn)問(wèn)這個(gè)問(wèn)題的不少,但是能解決我的問(wèn)題方案沒(méi)有。就在我以為這是一個(gè)不可解決的問(wèn)題的時(shí)候,我驚恐的發(fā)現(xiàn),QQ的item就不存在這個(gè)問(wèn)題,每次劃開(kāi),再快的速度滑動(dòng),都可以正常關(guān)閉,我擦擦,不能輸啊。
于是開(kāi)始看源碼,細(xì)節(jié)就不多說(shuō),結(jié)論如下:
該DOWN事件在ListView 的dispatchTouchEvent的時(shí)候是可以接收到的,但是在onTouchEvent方法里面就接收不到了。所以我們就去看看ListView的dispatchTouchEvent方法,ListView的dispatchTouchEvent是在ViewGroup里面,只看經(jīng)過(guò)我分析關(guān)鍵的部分:

@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;
                }

關(guān)鍵就在這里,我們可以看到有一句:// restore action in case it was changed,因?yàn)榭焖倩瑒?dòng),當(dāng)DOWN事件傳遞到onInterceptTouchEvent方法去判斷是不是該攔截的時(shí)候,MOVE事件來(lái)了,然后被restore了。
于是在onInterceptTouchEvent方法里面打印了一下是否有丟失DOWN事件,發(fā)現(xiàn)是:木有丟失?。?!好噠,問(wèn)題就在這里了。了解問(wèn)題在這里,這個(gè)問(wèn)題就容易解決了。重寫(xiě)onInterceptTouchEvent,判斷DOWN事件的位置是不是需要攔截,返回正確的TRUE or FALSE值就OK了嘍。
原文:https://my.oschina.net/zhibuji/blog/525488

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容