How to use Ontouch and Onclick for ImageButton?

in my application, I want two things to happen.

  • when I touch and drag the ImageButton, it should move with my finger.

    I used OnTouchListener() for this and it works great.

  • when I click the ImageButton button, it should close the activity.

    I used OnClickListener() for this and it also works great.

So here is my problem. whenever I move the ImageButton OnTouchListener is tigered and the ImageButton moves, OnClickListener also starts at the end when I release the button from the move.

How to use ontouch and onclick listeners on the same button without interfering with each other?

+54
android
Oct 23 '13 at 10:08 on
source share
11 answers

Try it, it can help you.

No need to set the onClick() onTouch() will handle both cases.

 package com.example.demo; import android.app.Activity; import android.os.Bundle; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageButton; public class MainActivity extends Activity { private GestureDetector gestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); gestureDetector = new GestureDetector(this, new SingleTapConfirm()); ImageButton imageButton = (ImageButton) findViewById(R.id.img); imageButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent arg1) { if (gestureDetector.onTouchEvent(arg1)) { // single tap return true; } else { // your code for move and drag } return false; } }); } private class SingleTapConfirm extends SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent event) { return true; } } } 
+119
Oct 23 '13 at 10:30
source share
β€” -

To have a Click Listener , DoubleClick Listener , OnLongPress Listener , Swipe Left , Swipe Right , Swipe Up , Swipe Down on Single View you need setOnTouchListener . i.e,

 view.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) { @Override public void onClick() { super.onClick(); // your on click here } @Override public void onDoubleClick() { super.onDoubleClick(); // your on onDoubleClick here } @Override public void onLongClick() { super.onLongClick(); // your on onLongClick here } @Override public void onSwipeUp() { super.onSwipeUp(); // your swipe up here } @Override public void onSwipeDown() { super.onSwipeDown(); // your swipe down here. } @Override public void onSwipeLeft() { super.onSwipeLeft(); // your swipe left here. } @Override public void onSwipeRight() { super.onSwipeRight(); // your swipe right here. } }); } 

To do this, you need the OnSwipeTouchListener class, which implements OnTouchListener .

 public class OnSwipeTouchListener implements View.OnTouchListener { private GestureDetector gestureDetector; public OnSwipeTouchListener(Context c) { gestureDetector = new GestureDetector(c, new GestureListener()); } public boolean onTouch(final View view, final MotionEvent motionEvent) { return gestureDetector.onTouchEvent(motionEvent); } private final class GestureListener extends GestureDetector.SimpleOnGestureListener { private static final int SWIPE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapUp(MotionEvent e) { onClick(); return super.onSingleTapUp(e); } @Override public boolean onDoubleTap(MotionEvent e) { onDoubleClick(); return super.onDoubleTap(e); } @Override public void onLongPress(MotionEvent e) { onLongClick(); super.onLongPress(e); } // Determines the fling velocity and then fires the appropriate swipe event accordingly @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { onSwipeRight(); } else { onSwipeLeft(); } } } else { if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { onSwipeDown(); } else { onSwipeUp(); } } } } catch (Exception exception) { exception.printStackTrace(); } return result; } } public void onSwipeRight() { } public void onSwipeLeft() { } public void onSwipeUp() { } public void onSwipeDown() { } public void onClick() { } public void onDoubleClick() { } public void onLongClick() { } } 
+31
Apr 16 '15 at 13:45
source share

The problem with the onClick and OnTouch event is that the moment you click (with the intent to click), it is assumed that the event will be OnTouch, so OnClick is never interpreted. Work around

 isMove = false; case MotionEvent.ACTION_DOWN: //Your stuff isMove = false; case MotionEvent.ACTION_UP: if (!isMove || (Xdiff < 10 && Ydiff < 10 ) { view.performClick; //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little even when you just click it } case MotionEvent.ACTION_MOVE: isMove = true; 
+9
Sep 24 '14 at 18:06
source share

I tried to apply the @Biraj solution in my project, but it did not work - I noticed that the SimpleOnGestureListener extension should override not only the onSingleTapConfirmed method, but also onDown . Due to the documentation :

If you return false from onDown (), as the GestureDetector.SimpleOnGestureListener does by default, the system assumes that you want to ignore the rest of the gesture, and the other GestureDetector.OnGestureListener methods will never be called

Below is a complete solution:

 public class MainActivity extends Activity { private GestureDetector gestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); gestureDetector = new GestureDetectorCompat(this, new SingleTapConfirm()); ImageButton imageButton = (ImageButton) findViewById(R.id.img); imageButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent arg1) { if (gestureDetector.onTouchEvent(arg1)) { // single tap return true; } else { // your code for move and drag } return false; } }); } private class SingleTapConfirm extends SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { /*it needs to return true if we don't want to ignore rest of the gestures*/ return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { return true; } } } 

I assume this may be caused by the difference of the GestureDetectorCompat, but I will follow the documentation and am going to use the second one:

If possible, support library classes should be used to ensure compatibility with devices running Android 1.6 and above.

+5
Feb 17 '16 at 15:41
source share

In MainActivity code MainActivity this is.

 public class OnSwipeTouchListener_imp extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_on_swipe_touch_listener); ImageView view = (ImageView)findViewById(R.id.view); view.setOnTouchListener(new OnSwipeTouchListener(OnSwipeTouchListener_imp.this) { @Override public void onClick() { super.onClick(); // your on click here Toast.makeText(getApplicationContext(),"onClick",Toast.LENGTH_SHORT).show(); } @Override public void onDoubleClick() { super.onDoubleClick(); // your on onDoubleClick here } @Override public void onLongClick() { super.onLongClick(); // your on onLongClick here } @Override public void onSwipeUp() { super.onSwipeUp(); // your swipe up here } @Override public void onSwipeDown() { super.onSwipeDown(); // your swipe down here. } @Override public void onSwipeLeft() { super.onSwipeLeft(); // your swipe left here. Toast.makeText(getApplicationContext(),"onSwipeLeft",Toast.LENGTH_SHORT).show(); } @Override public void onSwipeRight() { super.onSwipeRight(); // your swipe right here. Toast.makeText(getApplicationContext(),"onSwipeRight",Toast.LENGTH_SHORT).show(); } }); } } 

Then create the OnSwipeTouchListener Java class.

 public class OnSwipeTouchListener implements View.OnTouchListener { private GestureDetector gestureDetector; public OnSwipeTouchListener(Context c) { gestureDetector = new GestureDetector(c, new GestureListener()); } public boolean onTouch(final View view, final MotionEvent motionEvent) { return gestureDetector.onTouchEvent(motionEvent); } private final class GestureListener extends GestureDetector.SimpleOnGestureListener { private static final int SWIPE_THRESHOLD = 100; private static final int SWIPE_VELOCITY_THRESHOLD = 100; @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onSingleTapUp(MotionEvent e) { onClick(); return super.onSingleTapUp(e); } @Override public boolean onDoubleTap(MotionEvent e) { onDoubleClick(); return super.onDoubleTap(e); } @Override public void onLongPress(MotionEvent e) { onLongClick(); super.onLongPress(e); } // Determines the fling velocity and then fires the appropriate swipe event accordingly @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { boolean result = false; try { float diffY = e2.getY() - e1.getY(); float diffX = e2.getX() - e1.getX(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { if (diffX > 0) { onSwipeRight(); // Right swipe } else { onSwipeLeft(); // Left swipe } } } else { if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { if (diffY > 0) { onSwipeDown(); // Down swipe } else { onSwipeUp(); // Up swipe } } } } catch (Exception exception) { exception.printStackTrace(); } return result; } } public void onSwipeRight() { } public void onSwipeLeft() { } public void onSwipeUp() { } public void onSwipeDown() { } public void onClick() { } public void onDoubleClick() { } public void onLongClick() { } } 

Hope this lights you up :)

+3
Dec 05 '16 at 4:27
source share

Perhaps you can work with a boolean.

lets say Boolean isMoving = false;

 public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: isMoving = true; // implement your move codes break; case MotionEvent.ACTION_UP: isMoving = false; break; default: break; } 

and then in your onclick method check the boolean value. If it is false, then perform the click action, if true ... do not work.

 public void onClick(View arg0) { switch (arg0.getId()) { case R.id.imagebutton: if(!isMoving) { //code for on click here } default: break; } } 
+2
Oct 23 '13 at 10:15
source share

Clieck Listening Event; if the action action and action in your components is limited than calling onclicklistener. In this way, the onclick event is fired with touch detection. You can set onTouchListener and receive click events if the action and action are in the starting position of your components.

0
Oct. 23 '13 at 10:13
source share

Declare a private variable of the type: boolean hasMoved = false;

When the image button starts moving, set hasMoved = true

In your OnClickListener only if(!hasMoved) execution code means that the click function is executed only if the button has not been moved. Set hasMoved = false; after

0
Oct 23 '13 at 10:14
source share

Just use a boolean field and set it to true when OnTouchListener starts. after that, when OnClickListener wants to call you, you check the boolean field and if true do not act in your onClickListener.

  private blnTouch = false; private OnTouchListener btnOnTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub if (event.getAction()==MotionEvent.ACTION_DOWN){ blnOnTouch = true; } if (event.getAction()==MotionEvent.ACTION_UP){ blnOnTouch = false; } } }; private OnClickListener btnOnClickListener = new OnClickListener() { @Override public void onClick(View arg0) { if (blnOnTouch){ // Do Your OnClickJob Here without touch and move } } }; 
0
Oct 23 '13 at 10:21
source share

I hope I'm not late, but you can achieve this with a time counter. A click takes less than a second, so with that in mind ....

  long prev=0; long current = 0; long dif =0; public boolean onTouch(View view, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: prev = System.currentTimeMillis() / 1000; break; case MotionEvent.ACTION_UP: current = System.currentTimeMillis() / 1000; dif = current - prev; if (dif == 0) { //Perform Your Click Action } break; } } 

Hope this helps someone

0
Apr 13 '19 at 0:03
source share

You can distinguish between touching, clicking and scrolling, getting the difference in x, y values, for example:

 var prevY = 0 var prevX = 0 controls.setOnTouchListener { v, event -> when (event?.actionMasked) { MotionEvent.ACTION_DOWN -> { prevY = event.rawY.toInt() prevX = event.rawX.toInt() } MotionEvent.ACTION_UP->{ Log.d("Controls","Action up") var y = event.rawY.toInt() var x = event.rawX.toInt() val diffY = Math.abs(prevY - y) val diffX = Math.abs(prevX - x) if(diffX in 0..10 && diffY in 0..10){ // its a touch } //check diffY if negative, is a swipe down, else swipe up //check diffX if negative, its a swipe right, else swipe left } } true } 
0
Jul 08 '19 at 8:48
source share



All Articles