How to distinguish between move and click in onTouchEvent()?

后端 未结 10 2114
暖寄归人
暖寄归人 2020-11-28 22:30

In my application, I need to handle both move and click events.

A click is a sequence of one ACTION_DOWN action, several ACTION_MOVE actions and one ACTION_UP action

相关标签:
10条回答
  • 2020-11-28 23:08

    If you want to react on click only, use:

    if (event.getAction() == MotionEvent.ACTION_UP) {
    
    }
    
    0 讨论(0)
  • 2020-11-28 23:10

    To get most optimized recognition of click event We have to consider 2 things:

    1. Time difference between ACTION_DOWN and ACTION_UP.
    2. Difference between x's,y's when user touch and when release the finger.

    Actually i combine the logic given by Stimsoni and Neethirajan

    So here is my solution:

            view.setOnTouchListener(new OnTouchListener() {
    
            private final int MAX_CLICK_DURATION = 400;
            private final int MAX_CLICK_DISTANCE = 5;
            private long startClickTime;
            private float x1;
            private float y1;
            private float x2;
            private float y2;
            private float dx;
            private float dy;
    
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                // TODO Auto-generated method stub
    
                        switch (event.getAction()) 
                        {
                            case MotionEvent.ACTION_DOWN: 
                            {
                                startClickTime = Calendar.getInstance().getTimeInMillis();
                                x1 = event.getX();
                                y1 = event.getY();
                                break;
                            }
                            case MotionEvent.ACTION_UP: 
                            {
                                long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                                x2 = event.getX();
                                y2 = event.getY();
                                dx = x2-x1;
                                dy = y2-y1;
    
                                if(clickDuration < MAX_CLICK_DURATION && dx < MAX_CLICK_DISTANCE && dy < MAX_CLICK_DISTANCE) 
                                    Log.v("","On Item Clicked:: ");
    
                            }
                        }
    
                return  false;
            }
        });
    
    0 讨论(0)
  • 2020-11-28 23:11

    Below code will solve your problem

    
        @Override
            public boolean onTouchEvent(MotionEvent event) {
                switch(event.getAction()) {
                    case(MotionEvent.ACTION_DOWN):
                        x1 = event.getX();
                        y1 = event.getY();
                        break;
                    case(MotionEvent.ACTION_UP): {
                        x2 = event.getX();
                        y2 = event.getY();
                        dx = x2-x1;
                        dy = y2-y1;
    
                    if(Math.abs(dx) > Math.abs(dy)) 
                    {
                        if(dx>0) move(1); //right
                        else if (dx == 0) move(5); //click
                        else move(2); //left
                    } 
                    else 
                    {
                        if(dy>0) move(3); // down
                        else if (dy == 0) move(5); //click
                        else move(4); //up
                    }
                    }
                }
                return true;
            }
    
    
    0 讨论(0)
  • 2020-11-28 23:15

    I got the best results by taking into account:

    1. Primarily, the distance moved between ACTION_DOWN and ACTION_UP events. I wanted to specify the max allowed distance in density-indepenent pixels rather than pixels, to better support different screens. For example, 15 DP.
    2. Secondarily, the duration between the events. One second seemed good maximum. (Some people "click" quite "thorougly", i.e. slowly; I still want to recognise that.)

    Example:

    /**
     * Max allowed duration for a "click", in milliseconds.
     */
    private static final int MAX_CLICK_DURATION = 1000;
    
    /**
     * Max allowed distance to move during a "click", in DP.
     */
    private static final int MAX_CLICK_DISTANCE = 15;
    
    private long pressStartTime;
    private float pressedX;
    private float pressedY;
    
    @Override
    public boolean onTouchEvent(MotionEvent e) {
         switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                pressStartTime = System.currentTimeMillis();                
                pressedX = e.getX();
                pressedY = e.getY();
                break;
            }
            case MotionEvent.ACTION_UP: {
                long pressDuration = System.currentTimeMillis() - pressStartTime;
                if (pressDuration < MAX_CLICK_DURATION && distance(pressedX, pressedY, e.getX(), e.getY()) < MAX_CLICK_DISTANCE) {
                    // Click event has occurred
                }
            }     
        }
    }
    
    private static float distance(float x1, float y1, float x2, float y2) {
        float dx = x1 - x2;
        float dy = y1 - y2;
        float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
        return pxToDp(distanceInPx);
    }
    
    private static float pxToDp(float px) {
        return px / getResources().getDisplayMetrics().density;
    }
    

    The idea here is the same as in Gem's solution, with these differences:

    • This calculates the actual Euclidean distance between the two points.
    • This uses dp instead of px.

    Update (2015): also check out Gabriel's fine-tuned version of this.

    0 讨论(0)
  • 2020-11-28 23:16

    Here's another solution that is very simple and doesn't require you to worry about the finger being moved. If you are basing a click as simply the distance moved then how can you differentiate a click and a long click.

    You could put more smarts into this and include the distance moved, but i'm yet to come across an instance when the distance a user can move in 200 milliseconds should constitute a move as opposed to a click.

    setOnTouchListener(new OnTouchListener() {
        private static final int MAX_CLICK_DURATION = 200;
        private long startClickTime;
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    startClickTime = Calendar.getInstance().getTimeInMillis();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
                    if(clickDuration < MAX_CLICK_DURATION) {
                        //click event has occurred
                    }
                }
            }
            return true;
        }
    });
    
    0 讨论(0)
  • 2020-11-28 23:16

    Taking Jonik's lead I built a slightly more fine tuned version, that doesn't register as a click if you move your finger and then return to the spot before letting go:

    So here is my solution:

    /**
     * Max allowed duration for a "click", in milliseconds.
     */
    private static final int MAX_CLICK_DURATION = 1000;
    
    /**
     * Max allowed distance to move during a "click", in DP.
     */
    private static final int MAX_CLICK_DISTANCE = 15;
    
    private long pressStartTime;
    private float pressedX;
    private float pressedY;
    private boolean stayedWithinClickDistance;
    
    @Override
    public boolean onTouchEvent(MotionEvent e) {
         switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                pressStartTime = System.currentTimeMillis();                
                pressedX = e.getX();
                pressedY = e.getY();
                stayedWithinClickDistance = true;
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (stayedWithinClickDistance && distance(pressedX, pressedY, e.getX(), e.getY()) > MAX_CLICK_DISTANCE) {
                    stayedWithinClickDistance = false;
                }
                break;
            }     
            case MotionEvent.ACTION_UP: {
                long pressDuration = System.currentTimeMillis() - pressStartTime;
                if (pressDuration < MAX_CLICK_DURATION && stayedWithinClickDistance) {
                    // Click event has occurred
                }
            }     
        }
    }
    
    private static float distance(float x1, float y1, float x2, float y2) {
        float dx = x1 - x2;
        float dy = y1 - y2;
        float distanceInPx = (float) Math.sqrt(dx * dx + dy * dy);
        return pxToDp(distanceInPx);
    }
    
    private static float pxToDp(float px) {
        return px / getResources().getDisplayMetrics().density;
    }
    
    0 讨论(0)
提交回复
热议问题