Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SimpleOnGestureListener's onSingleTapUp never called

I created a custom component with both an onTouchListener and a gesture detector, I put the custom component in MainActivity's xml file which also has both onTouchEvent and a gesture detector. I want to detect single taps on the custom component and long presses on MainActivity, but it seems somehow the touch listeners interact and the single taps never get detected.

MainActivity.java:

public class MainActivity extends ActionBarActivity {
private GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    detector = new GestureDetector(this, new LongPressDetector());
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    detector.onTouchEvent(event);
    int action = event.getActionMasked();
    switch (action){
        case MotionEvent.ACTION_DOWN:{
            Log.d("TouchEvent", "Action_Down at MainActivity.java");
            break;
        }
    }
    return super.onTouchEvent(event);
}

private class LongPressDetector extends GestureDetector.SimpleOnGestureListener{
    @Override
    public boolean onDown(MotionEvent e) {
        Log.d("TouchEvent", "onDown at MainActivity.java");
        return super.onDown(e);
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Log.d("TouchEvent", "onLongPress at MainActivity.java");
        super.onLongPress(e);
    }
}
}

CustomView.java:

public class CustomView extends RelativeLayout {
private GestureDetector detector;

public CustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

private void init(Context c){
    LayoutInflater layoutInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    layoutInflater.inflate(R.layout.customview, this);
    detector = new GestureDetector(c, new TapDetector());
    this.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            detector.onTouchEvent(event);
            int action = event.getActionMasked();
            switch (action){
                case MotionEvent.ACTION_DOWN:{
                    Log.d("TouchEvent", "Action_Down at CustomView.java");
                    break;
                }
            }
            return false;
        }
    });
}

private class TapDetector extends GestureDetector.SimpleOnGestureListener{
    @Override
    public boolean onDown(MotionEvent e) {
        Log.d("TouchEvent", "onDown at CustomView.java");
        return super.onDown(e);
    }
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Log.d("TouchEvent", "onSingleTapUp at CustomView.java");
        return super.onSingleTapUp(e);
    }
}
}
like image 453
daxter1992 Avatar asked Feb 10 '15 09:02

daxter1992


People also ask

What is onSingleTapUp?

public boolean onSingleTapUp (MotionEvent e) Notified when a tap occurs with the up MotionEvent that triggered it. Parameters. e. MotionEvent : This value cannot be null .


3 Answers

If you are going to respond to a tap up you also need to return true from onDown, the default will return false (I'm guessing here).

At least for me anyway, I wasn't getting onSingleTapUp called for my code until I made sure onDown returned true.

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

I've seen other frameworks where 'up' events are only delivered if 'down' events are accepted, so I assumed that was what was happening here.

like image 182
Ian Walters Avatar answered Oct 19 '22 15:10

Ian Walters


there is no need for guessing (@alexndr) !!! look at sources

if u extends GestureDetector.SimpleOnGestureListener call to super.onDown(event)

    public boolean onDown(MotionEvent e) {
        return false;
    }

will return false but if u implement gesture detector listener then there is no super !

public class GestureDetector {
/**
 * The listener that is used to notify when gestures occur.
 * If you want to listen for all the different gestures then implement
 * this interface. If you only want to listen for a subset it might
 * be easier to extend {@link SimpleOnGestureListener}.
 */
public interface OnGestureListener {

    /**
     * Notified when a tap occurs with the down {@link MotionEvent}
     * that triggered it. This will be triggered immediately for
     * every down event. All other events should be preceded by this.
     *
     * @param e The down motion event.
     */
    boolean onDown(MotionEvent e);

ps. rule is simple:

if EVENT is CONSUMED RETURN TRUE if NOT RETURN FALSE

like image 24
ceph3us Avatar answered Oct 19 '22 16:10

ceph3us


You just need return true in your onTouchEvent(MotionEvent event).

Somewhat like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    detector.onTouchEvent(event);
    int action = event.getActionMasked();
    switch (action){
        case MotionEvent.ACTION_DOWN:{
            Log.d("TouchEvent", "Action_Down at MainActivity.java");
            break;
        }
    }
    return true;
}
like image 1
Vensent Wang Avatar answered Oct 19 '22 16:10

Vensent Wang