Passing touch events to the parent view
Thank you everyone for answering the question. But I was able to figure it out in a much simpler manner. Since my ViewSwitcher
wasn't detecting the touch event, I intercepted the touch event, called the onTouchEvent()
and returned false
. Here:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return false;
}
By overriding the onInterceptTouchEvent()
, I was able to intercept the touch event in the activity. Then I called the onTouchEvent()
in the ViewSwitcher
which handles the switching of the ListViews
. And finally by returning false
, it makes sure that the ViewGroup
doesn't consume the event.
Pass touch event to Parent View's onTouchListener in Android
The chain of events for a View group works like this - The dispatchEvent
is called. Then dispatchEvent
calls onInterceptTouchEvent
. if it returns false, then the touch events are passed on to the children of the ViewGroup. If any of the children consume the event (in this case the button consumes the event) i.e if they return true then the motionevent is not passed on to other methods. Since the button is clickable it returns true in this case.
If the onInterceptTouchEvent
method returns true then the child views are not given the motion event and instead that ViewGroup's onTouchListener
or onTouch
method are called.
Hence to pass on the touch event to the parent's (View Group) onTouchListener
make sure to return true in the onInterceptTouchEvent
method of the Parent (ViewGroup). You don't have to override onDispatchTouchEvent()
@Override
public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
Log.i(TAG,"PARENT.onInterceptTouchEvent");
return true;
}
For more details about how the touch navigation is done, please see this stack post
Passing touch events to ScrollView's Parent
You need to create a new class extending FrameLayout and ovverriding onInterceptTouchEvents
than you can perform your logic and decide which events must be sent to the scrollview and which ones must be handle inside the FrameLayout onTouchEvent
You can check the official documentation here
How to prevent a custom view passing touch events to parent viewpager
The ViewPager uses onInterceptTouchEvent()
to get the touches before its children. Take a look at the docs and overwrite onInterceptTouchEvent()
of the Pager as you like.
The onInterceptTouchEvent() method is called whenever a touch event is detected on the surface of a ViewGroup, including on the surface of its children. If onInterceptTouchEvent() returns true, the MotionEvent is intercepted, meaning it will be not be passed on to the child, but rather to the onTouchEvent() method of the parent.
Pass touch events from parent view to a specific subview
What you can do is to call the editText's onClick
in the onClick
method of the relative layout. This way all clicks on the relativeLayout
go to the editText
.
This should work see answer:
relativeLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
editText.setFocusableInTouchMode(true);
editText.requestFocus();
//needed for some older devices.
InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
}
});
I would do this programatically (in code), because it does not handle how the views look, but how they behave. Therefore, say in MVC, it belongs in the controller.
How to vary between child and parent view group touch events
- The
onTouchEvents()
for nested view groups can be managed by theboolean
onInterceptTouchEvent.
The default value for the OnInterceptTouchEvent
is false.
The parent's onTouchEvent
is received before the child's. If the OnInterceptTouchEvent
returns false, it sends the motion event down the chain to the child's OnTouchEvent
handler. If it returns true the parent's will handle the touch event.
However there may be instances when we want some child elements to manage OnTouchEvent
s and some to be managed by the parent view (or possibly the parent of the parent).
This can be managed in more than one way.
- One way a child element can be protected from the parent's
OnInterceptTouchEvent
is by implementing the requestDisallowInterceptTouchEvent.
public void requestDisallowInterceptTouchEvent (boolean
disallowIntercept)
This prevents any of the parent views from managing the OnTouchEvent
for this element, if the element has event handlers enabled.
- If the
OnInterceptTouchEvent
is false, the child element'sOnTouchEvent
will be evaluated. If you have a methods within the child elements handling the various touch events, any related event handlers that are disabled will return the OnTouchEvent to the parent.
This answer:
https://stackoverflow.com/a/13540006/3956566 gives a good visualisation of how the propagation of touch events passes through:
parent -> child|parent -> child|parent -> child views.
- Another way is returning varying values from the
OnInterceptTouchEvent
for the parent.
This example taken from Managing Touch Events in a ViewGroup and demonstrates how to intercept the child's OnTouchEvent
when the user is scrolling.
4a.
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onTouchEvent will be called and we do the actual
* scrolling there.
*/
final int action = MotionEventCompat.getActionMasked(ev);
// Always handle the case of the touch gesture being complete.
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
// Release the scroll.
mIsScrolling = false;
return false; // Do not intercept touch event, let the child handle it
}
switch (action) {
case MotionEvent.ACTION_MOVE: {
if (mIsScrolling) {
// We're currently scrolling, so yes, intercept the
// touch event!
return true;
}
// If the user has dragged her finger horizontally more than
// the touch slop, start the scroll
// left as an exercise for the reader
final int xDiff = calculateDistanceX(ev);
// Touch slop should be calculated using ViewConfiguration
// constants.
if (xDiff > mTouchSlop) {
// Start scrolling!
mIsScrolling = true;
return true;
}
break;
}
...
}
// In general, we don't want to intercept touch events. They should be
// handled by the child view.
return false;
}
Edit: To answer comments.
This is some code from the same link showing how to create the parameters of the rectangle around your element:
4b.
// The hit rectangle for the ImageButton
myButton.getHitRect(delegateArea);
// Extend the touch area of the ImageButton beyond its bounds
// on the right and bottom.
delegateArea.right += 100;
delegateArea.bottom += 100;
// Instantiate a TouchDelegate.
// "delegateArea" is the bounds in local coordinates of
// the containing view to be mapped to the delegate view.
// "myButton" is the child view that should receive motion
// events.
TouchDelegate touchDelegate = new TouchDelegate(delegateArea, myButton);
// Sets the TouchDelegate on the parent view, such that touches
// within the touch delegate bounds are routed to the child.
if (View.class.isInstance(myButton.getParent())) {
((View) myButton.getParent()).setTouchDelegate(touchDelegate);
}
How to handle touch event for child view in parent view
I resolved this by overriding 'onInterceptTouchEvent()' on MonthView, and posting the solution to help someone who would struggle with same issue.
I implemented GestureDetector to change month on 'onFling()' like below codes.
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean result = gestureDetector.onTouchEvent(event);
return result;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// right to left
if (e1.getX() - e2.getX() > minSwipeDistance) {
nextMonth();
}
// left to right
else if(e2.getX() - e1.getX() > minSwipeDistance) {
prevMonth();
}
// bottom to top
else if(e1.getY() - e2.getY() > minSwipeDistance) {
nextMonth();
}
//top to bottom
else if(e2.getY() - e1.getY() > minSwipeDistance) {
prevMonth();
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
Related Topics
Android - Supportmapfragment with Googlemaps API 2.0 Giving Illegalargumentexception
Work Around Canvas.Clippath() That Is Not Supported in Android Any More
Android - How to Enable Autostart Option Programmatically in Xiaomi Devices
Android Asynctask Testing with Android Test Framework
How to Auto-Start an Android Application
Camera Preview Image Data Processing with Android L and Camera2 API
Android Mask Bitmap on Canvas Gen a Black Space
Programmatically Add Id to R.Id
How to Execute the Dex File in Android with Command
How to Crop the Parsed Image in Android
How to Handle Outofmemoryerror
Autocompletetextview with Custom Adapter and Filter
How to Serialize My User Class for the Firebase Database and Fix This Error
Android 5.0 Material Design Style Navigation Drawer for Kitkat
Android Adb Stop Application Command Like "Force-Stop" for Non Rooted Device
How to Create an Android Library Jar with Gradle Without Publicly Revealing Source Code