I am intending to transfer a touch event from a parent view to its child. I tried some constructions but so far I have not succeeded to assign touch handling to another view, but only delegating touch handling from parent to child views, which is not quite the same.
This is what I like to achieve:
The green dot is a Touch Down Event on the parent, then I am dragging towards another view, which is than picked up on the blue spot (firing Touch-Down on the child view) and from this point the parent view is not involved anymore, like I would have touched the child in the first place.
I could delegate the touch event by extending the parents onTouchEvent method, and then calling child.dispatchTouchEvent(), when entering the childs view-bounds, but I would like to avoid the parents involvement.
From the View.OnTouchListener documentation, the return of an OnTouch() is:
Returns
True if the listener has consumed the event, false otherwise.
Basically, if you want the parent to react to the onTouchListener, return false. If you want it to not react, return true.
Related
I have a custom ZoomableViewGroup that overrides onTouchEvent to handle pan/fling movements, and uses ScaleGestureDetector.SimpleOnScaleGestureListener to handle zoom gestures. This ZoomableViewGroup works fine until I try to use onTouch in children of the ViewGroup.
Inside this ZoomableViewGroup I have multiple ImageViews that serve as buttons. I would like the functionality of the parent to take precedent over the onTouch of the children. As it stands it seems the child ImageViews are intercepting touchevents and not passing them to it's parent.
I would like to know what a good method of ensuring that a parent's touch functionality is preserved over it's children's touch functionality.
Any help or suggestions would be greatly appreciated!
EDIT:
Your response has been extremely helpful Jason, I think i'm starting to make sense of this situation better now. I've been messing around with my zoomable view groups onInterceptTouchEvent method, but am still a bit confused
you touch the screen over an ImageView inside of my zoomable ViewGroup,
ViewGroup.onInterceptYouchEvent gets ACTION_DOWN
i want my ViewGroup to act IF the event is a pan or zoom gesture, so I will return 'true'for ACTION_DOWN
it appears that when my viewgroup consumes ACTION_DOWN event, it sends my ImageView.onTouch 'ACTION_CANCEL'
I want my ImageView.onTouch method to respond to an ACTION_UP event if the ACTION_MOVE preceding it is less than a slop value.
how is my ImageView supposed to get the relevant ACTION_UP info if it's aleady recieved an ACTION_CANCEL from it's parent ViewGroup?
please correct me if I'm interpreting what's happening wrong here too! Thanks Again!
The basic idea is to override onInterceptTouch in the parent view and provide logic there for whether or not to pass on the touch to the child view (return false) or to actually allow the parent view to intercept/consume the touch (return true). Your logic can be spatial (perhaps the edges of the parent view are special, but not the interior), or gestural (perhaps horizontal swipes trigger something at the parent view level and vertical swipes trigger something at the child view level, or, in your case, simple taps get passed to the child buttons, but two finger gestures get consumed by the parent).
I have a custom linearlayout in which I have two gridviews.
I want to have multitouch on the complete linearlayout, ie, first touch can be in one gridview and second touch can be in another gridview and the linear layout should be able to get multitouch events for this (ACTION_DOWN and ACTION_POINTER_DOWN). I am able to get this by overriding onInterceptTouchEvent in my custom layout.
Now I also want the gridview to scroll independently if required. Although gridview is a scrollable view, it is not able to do so, because I have intercepted the 'down' event. I see that when I try to scroll two events are generated : 'ACTION_DOWN' and 'ACTION_MOVE'.
Since I need ACTION_DOWN for multitouch use case I want it to be sent to linearlayout as well.
Is there a possibility to send the ACTION_DOWN event to both the linearlayout as well as my child view which is gridView in this case?
Need help.
You don't have to intercept ACTION_DOWN just to monitor that it flowed through your container view. In other words, you can override onInterceptTouchEvent() to monitor the touch events before they are passed to the appropriate child view by the framework, but as long as you don't screw with the return value it won't actually steal subsequent touch events from the grid elements. For example:
public boolean onInterceptTouchEvent (MotionEvent ev)
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
//Touchdown!
}
//Don't modify this and touch interaction will happen normally
return super.onInterceptTouchEvent(ev);
}
This allows you to see the event without taking it away from the child element(s).
I am having a gesture listener attached to a view and I have onSingleTap Event handled.
It handles it properly if I tap anywhere in the view. But say if the View is having any subview and if I am tapping the subview the event does not get triggered.
Is there a way to pass this touch from child to parent? And also the children contains BUTTONS. so if the press is on a child button it should not pass the touch to parent. Otherwise it must pass it to parent. Anyway to achieve this?
You can override the Activity's dispatchTouchEvent(MotionEvent) in order to handle the dispatching yourself.
A good handling would be to first check if it triggers the gesture in your view and if not just call super.dispatchTouchEvent(MotionEvent);
The one thing you have to care about while doing this is to keep the gestures coherent with the rest of the platform.
How do I block onTouchEvent from a view's siblings? I have a ViewGroup with a custom button in it. When the button receives an OnTouchEvent, I want to block further OnTouchEvents from going to the button's siblings. I do want to continue receiving OnTouchEvent in the button.
I think you should use a custom ViewGroup as well. In order to get what you want you should override the onInterceptTouchEvent() method, like stated here:
The onInterceptTouchEvent() method gives a parent the chance to see
any touch event before its children do. If you return true from
onInterceptTouchEvent(), the child view that was previously handling
touch events receives an ACTION_CANCEL, and the events from that point
forward are sent to the parent's onTouchEvent() method for the usual
handling. onInterceptTouchEvent() can also return false and simply spy
on events as they travel down the view hierarchy to their usual
targets, which will handle the events with their own onTouchEvent().
Basically, according to your own logic (button onTouchEvent, etc), you should instruct your ViewGroup.onInterceptTouchEvent() to return true if MotionEvent raw coords are not included in the visible rect of your button.
I tried to understand how Android handle touch event and got a little bit confused. From what I understand touch event are send to the root view and pass down to the children.
I have a FrameLayout that is a container for Fragment.
First fragment view is a ScrollView, second one is some kind of Gallery (HorizontalListView) and the last one is also FrameLayout. Only one fragment in the layout each time.
What I want to do is to identify user swipes on the screen, for the app use. I want to count the swipes and do something after some number of swipes.
I tried to put a OnTouchListener on the top FrameLayout but it doesn't get called when the child is the ScrollView or the Gallery. I tried to return false and also true in the end of onTouch, but I get same result - it's never being called.
How can I do it?
I just want to "transparently" handle the touch events and passing them on like I didn't even touch them.
My understanding is that it actually goes the other direction. The Child views get their event triggered first (sort of). The root view get's it's dispatchTouchEvent() called, which propagates the event down to the children's onTouchEvent(), and then, depending on whether they return true or false, the parent's onTouchEvent() is called.
The normal solution for intercepting things like this is to override dispatchTouchEvent(MotionEvent ev) in one's activity like so:
#Override
public boolean dispatchTouchEvent (MotionEvent ev) {
// Do your calcluations
return super.dispatchTouchEvent(ev);
}
The documentation for this one is here. Note that you can also override that method in any ViewGroup (such as a FrameLayout, etc)