I want to listen to touch events for a viewFlipper. I've been able to listen to touch events in my activity and then modify the viewFlipper but these events are fired wherever the user is within the activity and I need to capture touch events specifically on the viewFlipper. I have tried adding setOnTouchListener but it is not called. I'm assuming the viewFlippers children (webviews) are 'consuming' the touch events.
One solution would be to setOnTouchListener's to each of the webviews but this feels like a hack. Does anyone know another way?
Thanks,
Ian
Sorry if this is a double post - but my previous post seems to have vanished.
Use ViewGroup.onInterceptTouchEvent(MotionEvent)
You should Reference the Android Documentation as it's usage is quite complicated.
Basic Summary of use:
You receive the touch event here. If you want to consume it, return true and control will be passed to the ViewFlipper's onTouchEvent(). Return false and it will continue to be passed to the child. onTouchEvent() should also return true to ensure all further events are returned to the ViewFlipper's method. The child will also receive the original event with the action ACTION_CANCEL.
Finally It worked for me. Return true by default to get multiple calls on this listener.
viewFlipper.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (this.gestureDetector.onTouchEvent(event)) {
return false;
}
return true;
}
});
I was having the same problem and found your page trying to google for an answer.
After a few very frustrating attempts I ended up finding a quite easy solution, I'm still listening to the touch on the whole activity just like you did, but on the OnTouchEvent I filter if the ViewFlippers is touched or not:
#Override
public boolean onTouchEvent(MotionEvent event) {
if(mFlip.isInTouchMode()){
return gestureDetector.onTouchEvent(event);
} else{
return super.onTouchEvent(event);
}
}
hope it helps!
Related
How can I detect any gesture in my Activity, even with many things there (Layouts, Images, RecyclerViews, etc).
I intent to create an gesture that can be done at any time.
Is it possible?
I've tried this:
findViewById(android.R.id.content).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("GESTURE", "GESTURE");
return false;
}
});
But it's not working. I think it's because the others views is intercepting the event.
Idk if is it possible to detect the gesture above the activity, like in the window.
Thank you!
You can, but it's a bit tricky. Read up on touch handling and especially onInterceptTouchEvent, which can be used on a parent to intercept touches going to the children.
You would implement that method in a (custom) root view, and then do your gesture magic in there.
Some valuable info here: Android: Difference between onInterceptTouchEvent and dispatchTouchEvent?
I'm working on an SDK in which I set an OnTouchListener to 2 different views from two different classes that each one of them needs to handle the same touch events for its purposes.
Until now I only needed the ACTION_DOWN event in one of them so the method was written as follows:
#Override
public boolean onTouch(View v, MotionEvent event) {
ABLogger.d("onTouch Walkthrough handler");
if (event.getAction() != MotionEvent.ACTION_DOWN) {
return false;
}
return onAction(v, event);
}
And it was working well as I was receiving the ACTION_DOWN event passing false as a return value, and the following events would be propagated to the next view and its listener in line.
Now I need to test in this method that scroll wasn't committed, in order to do that I need to receive here the ACTION_UP event as well. But I won't receive it unless I pass true in the return of this method. But if I do that the next listener in line does not receive the events anymore.
The question is: How can I receive all the events in both listeners, or at least receive the event in one of them and force it to pass the event to the second one as well?
I have a custom view that I created by extending the View class. My custom view overrides the onTouchEvent.
I want to be able to turn the view's ability to listen on and off. I need to do that from within the view. Does anyone know how I can accomplish this? Simply calling
setEnabled(false);
does not work.
Try by setting the following
setOnTouchListener(null)
I'm not sure if this is the right solution but it works:
this.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return true;
}
});
This blocks other touch related Listeners from receiving the Event, so onTouchEvent won't be invoked.
you can use setOnTouchListener(null) to go back to your normal state so that your onTouchEvent works again.
if you had figured out a better solution i hope that you post it.
I have a simple layout:
<CustomFrameLayout>
<ListView />
</CustomFrameLayout>
In my CustomFrameLayout, I am overriding:
onInterceptTouchEvent(MotionEvent event);
and returning false. When scrolling the ListView, the onInterceptTouchEvent receives the ACTION_DOWN and the first ACTION_MOVE event. Then, the ListView seems to take over and onInterceptTouchEvent fails to receive the following ACTION_MOVE events.
This goes against what the documentation states:
For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
I have looked into requesting touch events to not be intercepted at the ListView level.
requestDisallowInterceptTouchEvent(boolean disallowIntercept)
This does not seem to have any effect. Should I be calling this on the ListView cell view's as well? Is there something else I am missing? I am testing on Android 4.4
Thanks.
you should return true in onInterceptTouchEvent(MotionEvent event);
true indicates that you are willing to receive further touch actions where as false indicates you are not interested further actions...
I have decided to override this method instead. Here, I can guarantee that I can intercept all touch events before they are dispatched to and potentially consumed by the child views.
dispatchTouchEvents(MotionEvent event);
I know that for an Android view, if I return true to onTouchEvent, then it means that you want to continue receiving events for the current gesture. If you return false it should not process more events for the current gesture
However I'd like to try to detect whether a gesture is a click or a hold/drag event, so I return true to the initial ACTION_DOWN event, until some number of milliseconds has elapsed, at which point I timeout and recognize the gesture as a hold/drag instead of a click.
Once the timeout has elapsed, I'd like to return false to further onTouchEvents, so that I can stop receiving events and let the parent view manage the rest of the drag.
However I seem to notice that once you return true for the first event, then it receives all further events with the associated gesture, even after I continually return false to later events. It seems the return value only matters for the very first event, after which it is ignored.
Is there any way to stop receiving onTouchEvent, and therefore pass it to the parent, once you have accepted the first event in a gesture?
Remember that the boolean return value of onTouchEvent only indicates whether the event has been handled or not - you should still receive events when the user is in the middle of a gesture.
Generally, you can tailor the behavior however you want in your handler:
private boolean hasHandledGesture = false;
public boolean onTouchEvent( MotionEvent event ){
if( !hasHandledGesture ){
// Do your actual handling here for the first event
return true;
} else {
return super.onTouchEvent( event );
}
}
However, I think in your case you'd be better off creating a handler that registers via setOnLongClickListener. Not only will it make your life easier, but you'll also let the OS decide how long it takes to make a long press. This is the best choice if you want to make the length of the press match the rest of the system, helping the overall app's native look and feel.
If you want to catch some more complex events, you might want to look at using a GestureDetector, but it probably is more complexity than you need if you're just detecting a long press.