為自定義的View添加長按事件


以前開發畫板組件時,要添加一個長按監聽事件,這個畫板實際上就是繼承自View的一個自定義組件。

首先,設置好長按事件發生時要觸發的操作:

  private class LongPressRunnable implements Runnable {

        private int x, y;

        public void setPressLocation(float x, float y) {
            this.x = (int) x;
            this.y = (int) y;
        }

        @Override
        public void run() {
            Log.i("發生長按事件,位置在:" + x + "、" + y);
        }

    }

接下來,編寫自定義的View,重點在覆寫dispatchTouchEvent(MotionEvent)方法:

public class MyView extends View {

        ...

    /**
     * 當長按事件發生時,要觸發的任務
     */
    private LongPressRunnable longPressRunnable = new LongPressRunnable();

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        if (longPressRunnable != null) {

            //TODO 這里可以增加一些規則,比如:模糊XY的判定,使長按更容易觸發

            removeCallbacks(longPressRunnable);

            if (event.getAction() == MotionEvent.ACTION_DOWN
                    && event.getPointerCount() == 1) {
                postCheckForLongTouch(event.getX(), event.getY());
            }
        }

        return true;
    }

    private void postCheckForLongTouch(float x, float y) {

        longPressRunnable.setPressLocation(x, y);
       postDelayed(longPressRunnable,
500); } }

原理很簡單,長按事件的本質是:手指觸摸某個點保持不移動,也就是touch的時候僅僅發生ACTION_DOWN事件,不發生ACTION_MOVE和ACTION_UP事件,這樣經過一定時間(這里是500毫秒)則成功觸發長按事件。

所以一個長按事件的周期是On Touch Down ---> 500ms ---> On Long Press。

接下來分析上面的實現:當我們收到Touch事件時,不管是什么事件,先刪除上一次設置好的longPressRunnable,

removeCallbacks(longPressRunnable);

這意味着上一次觸摸周期沒有觸發長按操作。

然后判斷事件類型,如果是“單指ACTION_DOWN”事件則表明有可能會觸發長按操作,那么我們通過View.postDelayed()方法將longPressRunnable放進這個View所在線程的任務隊列中,並延遲500毫秒執行,

if (event.getAction() == MotionEvent.ACTION_DOWN && event.getPointerCount() == 1) {
     postCheckForLongTouch(event.getX(), event.getY());
}

 

private void postCheckForLongTouch(float x, float y) {
    longPressRunnable.setPressLocation(x, y);
    postDelayed(longPressRunnable, 500);
}

 

如果在這500毫秒內,用戶的手指沒有移動或抬起,也就是不會有任何touch事件到來,則該longPressRunnable會在500毫秒后運行,一個長按操作就完成了。

如果在這500毫秒內用戶的手指移動或抬起了,那么新的touch事件到來,longPressRunnable也會被移除。

以上就是整個實現,這個實現有個需要優化的地方,就是//TODO那里,由於人的手指並沒有那么精細,在長按過程中可能會有一點移動,這往往會導致長按失敗,所以我們可以在//TODO那里添加對ACTION_MOVE事件的處理,忽略一些細微的移動事件,留給讀者自行實現吧:D


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM