Невозможно одновременно обрабатывать события click и touch

Я пытаюсь обработать события касания и щелкнуть события на кнопке. Я делаю следующее:

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

Когда какой-либо один слушатель зарегистрирован, все работает нормально, но когда я пытаюсь использовать их, срабатывают только события касания. Любое обходное решение? Что я делаю не так?

Существует тонкое, но очень важное различие между ClickListener и TouchListener . TouchListener выполняется до того, как представление может ответить на событие. ClickListener получит свое событие только после того, как представление обработало его.

Поэтому, когда вы касаетесь вашего экрана, TouchListener выполняется первым, и когда вы возвращаете true для своего события, ClickListener никогда не получит его. Но если вы нажмете трекбол своего устройства, ClickListener должен быть запущен, потому что TouchListener не ответит на него.

Это немного сложно.

Если вы установите onTouchListener вам нужно вернуть true в ACTION_DOWN , чтобы сообщить системе, что я использовал это событие, и он не будет просачиваться к другим слушателям.

Но тогда OnClickListener не будет запущен.

Так что вы можете подумать, я просто сделаю свое дело и вернусь к false чтобы получить клики тоже. Если вы это сделаете, он будет работать, но вы не будете подписаны на другие предстоящие события касания ( ACTION_MOVE , ACTION_UP ). Поэтому единственным вариантом является возrotation true там, но тогда вы не будете получать никаких событий кликов, как мы сказали ранее.

Поэтому вам нужно выполнить щелчок вручную в ACTION_UP с помощью view.performClick()

Это сработает.

Спасибо @urSus за отличный ответ
Но в этом случае каждое нажатие будет выполнять щелчок, даже ACTION_MOVE
Предполагая, что вы хотите разделить событие move событие click вы можете использовать небольшой трюк
определите boolean поле и используйте вот так:

  @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: shouldClick = true; . . break; case MotionEvent.ACTION_UP: if (shouldClick) view.performClick(); break; case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: //Do your stuff shouldClick = false; break; } rootLayout.invalidate(); return true; } 

Полагаю, вы вернулись в свой OnTouchListener ? Это будет потреблять событие, поэтому оно не будет отправлено для дальнейшей обработки.

На стороне примечания – в чем смысл иметь как клик, так и прикосновение слушателя?

Вы должны вернуть false в свой OnTouchListener тогда будет обработан ваш OnClickListener .

 button.setOnTouchListener(this); 

Внесите интерфейс и код здесь:

 @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (view.getId()) { case R.id.send: switch(motionEvent.getAction()){ case MotionEvent.ACTION_DOWN: //when the user has pressed the button //do the needful here break; case MotionEvent.ACTION_UP: //when the user releases the button //do the needful here break; } break; } return false; } 

Чтобы сделать оба события возможными в gridview, только, возвращая прикосновение слушателя «false» следующим образом, это сработало для меня.

 **GridView myView = findViewById(R.id.grid_view); myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { // ... Respond to touch events return false; } });** 

таким образом, оба события могут быть достигнуты

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

Все вышеприведенные ответы говорят о том, что мы не можем обрабатывать как setOnTouchListener и setOnClickListener .
Тем не менее, я вижу, что мы можем обрабатывать оба путем return false в setOnTouchListener

пример

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

Когда я нажимаю на Button , logcat будет отображаться как

 I/TAG: onTouch 0 I/TAG: onTouch 1 I/TAG: onClick 
Давайте будем гением компьютера.