Can't handle both click and touch events simultaneously

后端 未结 12 2034
时光说笑
时光说笑 2020-12-01 03:45

I am trying to handle touch events and click events on a button. I do the following:

button.setOnClickListener(clickListener);
button.setOnTouchListener(touc         


        
相关标签:
12条回答
  • 2020-12-01 04:06

    You should return false in your OnTouchListener then your OnClickListener will be also handled.

    0 讨论(0)
  • 2020-12-01 04:08

    thanks to @Nicolas Duponchel this is how i achieved both onClick and onTouch events

    private short touchMoveFactor = 10;
        private short touchTimeFactor = 200;
        private PointF actionDownPoint = new PointF(0f, 0f);
        private long touchDownTime = 0L;
    
     @Override
        public boolean onTouchEvent(MotionEvent event) {
            final int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN: {
                Log.d(TAG, "onTouch: _____________ACTION_DOWN");
                        actionDownPoint.x = event.getX();
                        actionDownPoint.y = event.getY();
                        touchDownTime = System.currentTimeMillis();
                        break;
                    }
                    case MotionEvent.ACTION_UP: {
                        Log.d(TAG, "onTouch: _____________ACTION_UP");
               //check if the user's finger is still close to the point he/she clicked 
                            boolean isTouchLength = (Math.abs(event.getX() - actionDownPoint.x)
                                    + Math.abs(event.getY() - actionDownPoint.y)) < touchMoveFactor;
            //check if it's not been more than @touchTimeFactor=200 ms
                            boolean isClickTime = System.currentTimeMillis() - touchDownTime < touchTimeFactor;
                                 if (isTouchLength && isClickTime) performClick();
        //ACTION_UP logic goes below this line
         .....
         .....
    
                        break;
                    }
    
                    case MotionEvent.ACTION_MOVE: {
    //move method should not work if the click was too short i.e click time +100 ms
                    if (System.currentTimeMillis() - touchDownTime < touchTimeFactor+100) return true;
                    Log.d(TAG, "onTouch: _____________ACTION_MOVE");
    
    // move method logic goes below this line
      .....
      .....
        }}}
    
    0 讨论(0)
  • 2020-12-01 04:08
    ## Exact working solution for both click action and touch listener(dragging) ##
    
    private int initialX;
    private int initialY;
    private float initialTouchX;
    private float initialTouchY;
    private float CLICK_ACTION_THRESHOLD = 0.5f;
    private float startX;
    private float startY;
    
     @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (view.getId()) {
            case R.id.chat_head_profile_iv:
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //remember the initial position.
                        initialX = params.x;
                        initialY = params.y;
                        startX = event.getX();
                        startY = event.getY();
                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        float endX = event.getX();
                        float endY = event.getY();
                        if (shouldClickActionWork(startX, endX, startY, endY)) {
                            openScreen();// WE HAVE A CLICK!!
                        }
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        //Calculate the X and Y coordinates of the view.
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);
    
                        //Update the layout with new X & Y coordinate
                        mWindowManager.updateViewLayout(mChatHeadView, params);
                        return true;
                }
                break;
        }
        return true;
    }
    
    private boolean shouldClickActionWork(float startX, float endX, float startY, float endY) {
        float differenceX = Math.abs(startX - endX);
        float differenceY = Math.abs(startY - endY);
        if ((CLICK_ACTION_THRESHOLD > differenceX) && (CLICK_ACTION_THRESHOLD > differenceY))
            return true;
        else
            return false;
    }
    
    0 讨论(0)
  • 2020-12-01 04:14

    There is a subtle, yet very important difference between the ClickListener and the TouchListener. The TouchListener is executed before the view can respond to the event. The ClickListener will receive its event only after the view has handled it.

    So when you touch your screen, the TouchListener is executed first and when you return true for your event, the ClickListener will never get it. But if you press the trackball of your device, the ClickListener should be fired because the TouchListener will not respond to it.

    0 讨论(0)
  • 2020-12-01 04:17

    Its a little tricky.

    If you set onTouchListener you need to return true in ACTION_DOWN, to tell the system that I have consumed the event and it won't trickle down to other listeners.

    But then OnClickListener won't be fired.

    So you might think, I will just do my thing there and return false so I can receive clicks too. If you do so, it will work, but you won't be subscribed to other upcoming touch events (ACTION_MOVE, ACTION_UP) Therefore, the only option is to return true there, but then you won't receive any click events as we said previously.

    So you need to perform the click manually in the ACTION_UP with view.performClick()

    This will work.

    0 讨论(0)
  • 2020-12-01 04:20

    All above answer is said that we can not handle both setOnTouchListener and setOnClickListener.
    However, I see we can handle both by return false in setOnTouchListener

    Example

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        button = findViewById(R.id.button)
        button.setOnClickListener {
            Log.i("TAG", "onClick")
        }
    
        button.setOnTouchListener { v, event ->
            Log.i("TAG", "onTouch " + event.action)
            false
        }
    }
    

    When I click at Button, logcat will display like

    I/TAG: onTouch 0
    I/TAG: onTouch 1
    I/TAG: onClick
    
    0 讨论(0)
提交回复
热议问题