Passing Touch Events to the Parent View

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

  1. The onTouchEvents() for nested view groups can be managed by the boolean 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 OnTouchEvents 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.


  1. 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.


  1. If the OnInterceptTouchEvent is false, the child element's OnTouchEvent 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.


  1. 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



Leave a reply



Submit