Praveen Thamizhazhagan
Praveen Thamizhazhagan

Reputation: 841

how to use both Ontouch and Onclick for an ImageButton?

in my app, i want two things to happen.

  1. when i touch and drag the ImageButton, it should move along with my finger.

    i used OnTouchListener() for this and it works fine.

  2. when i click the ImageButton, it should close the activity.

    i used OnClickListener() for this and it also works fine.

So, here is my problem. whenever i move the ImageButton OnTouchListener is tirggered and the ImageButton moves, the OnClickListener is also triggered at the end when i am releasing the button from moving.

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

Upvotes: 69

Views: 77087

Answers (12)

Vikash Sharma
Vikash Sharma

Reputation: 539

Perfect example for Both touch n tap both    
private void touchNtap() {
            GestureDetector gestureDetector = new GestureDetector(itemView.getContext()
                    , new SingleTapConfirm());


            imageView.setOnTouchListener(new View.OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (gestureDetector.onTouchEvent(event)) {
                        // program for click events
                        gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
                            @Override
                            public boolean onSingleTapConfirmed(MotionEvent e) {
                                Log.d(TAG, "onSingleTapConfirmed() returned: " + true);
                                return false;
                            }

                            @Override
                            public boolean onDoubleTap(MotionEvent e) {
                                Log.d(TAG, "onDoubleTap() returned: " + true);
                                return false;
                            }

                            @Override
                            public boolean onDoubleTapEvent(MotionEvent e) {
                                Log.d(TAG, "onDoubleTapEvent() returned: " + true);
                                return false;
                            }
                        });
                        return true;
                    }else {
                        //program for touch events
                    }
                    return false;
                }
            });
        }
Create a Inner class 

    private class SingleTapConfirm extends GestureDetector.SimpleOnGestureListener {

            @Override
            public boolean onSingleTapUp(MotionEvent event) {
                return true;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                return true;
            }
        }

Upvotes: 0

ozmank
ozmank

Reputation: 763

You can differentiate between touch, click and swipe by getting the difference in the x,y values like:

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
            }

Upvotes: 1

Dr Adams
Dr Adams

Reputation: 276

Hope I'm not too late but you can achieve this by 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 it helps out someone

Upvotes: 1

Agilarasan anbu
Agilarasan anbu

Reputation: 2805

In MainActivity code this.

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 a 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 u:)

Upvotes: 6

Biraj Zalavadia
Biraj Zalavadia

Reputation: 28484

Try this, It may help you

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

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

}

Upvotes: 141

Krzysztof Skrzynecki
Krzysztof Skrzynecki

Reputation: 2525

I've tried to apply @Biraj solution in my project and it didn't work - I've noticed that extension of SimpleOnGestureListener should not only override onSingleTapConfirmed method, but onDown as well. Due to documentation:

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

Below is complex 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 suppose, that this behaviour can be caused by difference GestureDetectorCompat, but I'll follow documentation and I'm going to use second one:

You should use Support Library classes where possible to provide compatibility with devices running Android 1.6 and higher

Upvotes: 6

Jaydipsinh Zala
Jaydipsinh Zala

Reputation: 16798

To have Click Listener, DoubleClick Listener, OnLongPress Listener, Swipe Left, Swipe Right, Swipe Up, Swipe Down on Single View you need to 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.
            }
        });

}

For this you need OnSwipeTouchListener class that 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() {

}
}

Upvotes: 36

Deepika Anand
Deepika Anand

Reputation: 305

The problem with onClick and OnTouch event is that the moment you Click(with the intention to Click) it assumes the event to be OnTouch thus OnClick is never interpreted. The 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;

Upvotes: 9

rmuller
rmuller

Reputation: 1837

Maybe 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 for the boolean. If it is false, then perform the click action, if true ... do not act.

public void onClick(View arg0) {

    switch (arg0.getId()) {

    case R.id.imagebutton:
        if(!isMoving) {
                   //code for on click here
                }
    default:
        break;
    }
}

Upvotes: 2

Majid Daeinejad
Majid Daeinejad

Reputation: 1037

Simply use a boolean field and set it to true value when your OnTouchListener is triggered. after that when the OnClickListener wants to trigger you will check the boolean field and if true don't act anything 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
        }

    }
};

Upvotes: 0

Amulya Khare
Amulya Khare

Reputation: 7698

Declare a private variable like: boolean hasMoved = false;

When the image button begins to move, set hasMoved = true

In your OnClickListener execute code only if(!hasMoved) -- meaning perform on click functionality only if the button has not moved. Set hasMoved = false; afterwards

Upvotes: 0

nurisezgin
nurisezgin

Reputation: 1570

Clieck Listener event; if actiondown and action up in your components bounds than call onclicklistener. Thus onclick event activate with touch detection. You could only set onTouchListener and receive click events if action up and action down in your components start position.

Upvotes: 0

Related Questions