Android-Touch event detection for both parent and child views simultaneously

3.1k views Asked by At

Currently following is the layout of my application:

       LinearLayout
            ----Button
               ----ScrollView
                  ----RelativeLayout
                     ----EditText

I have created one transparent LinearLayout over all of these,implemented OnTouchListener and inside OnTouch(),returned false. So, all controls are moved below childrens.But on LinearLayout, I am not able to handle ACTION_MOVE actions since MotionEvent object is not consumed by this layout. Is there any way that I can detect all touch event both in parent and child views ?

2

There are 2 answers

4
Kartheek On

You could accomplish that by overriding dispatchTouchEvent in the layout.

public class MyFrameLayout extends LinearLayout {
    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        // do what you need to with the event, and then...
        return super.dispatchTouchEvent(e);
    }
}

Then use that layout in place of the usual FrameLayout:

    <com.example.android.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="10dip"
        android:id="@+id/rootview">

  ...

You could also skip the super call entirely if you need to prevent child views from receiving the event, but I think this would be rare.

This answer is based on the reference of Romain guy answer.

0
Nguyen Tan Dat On

In my experience, dispatchTouchEvent() method should not be overridden since it's kind of difficult to control. My suggestion is onInterceptTouchEvent() method. This option is not supported for overriding by Android. You could hijack it by creating your own View, here is a snippet which extends from RelativeLayout:

public class InterceptTouchRelativeLayout extends RelativeLayout{

public interface OnInterceptTouchListener{
    boolean onInterceptTouch(MotionEvent ev);
}

private OnInterceptTouchListener onInterceptTouchListener;

public InterceptTouchRelativeLayout(Context context) {
    super(context);
}

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

public InterceptTouchRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return onInterceptTouchListener.onInterceptTouch(ev);
}

public void setOnInterceptTouchListener(OnInterceptTouchListener onInterceptTouchListener) {
    this.onInterceptTouchListener = onInterceptTouchListener;
}

}

And use it as usual,

myView.setOnInterceptTouchListener(new InterceptTouchRelativeLayout.OnInterceptTouchListener() {
        @Override
        public boolean onInterceptTouch(MotionEvent ev) {
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    // Parent didn't steal this touch event if return false this case.
                    return false;

                case MotionEvent.ACTION_MOVE:
                    // Parent didn't steal this touch event if return false this case.
                    return false;

                case MotionEvent.ACTION_UP:
                    // Parent didn't steal this touch event if return false this case. However, please notice, it's too late for the parent to steal this touch event at this time, it won't work anymore.
                    return true;
            }

            return false;
        }
    });

Anyway, my advice is to study more the flow of that view/ view group controls touch event. And this is an explanation how onInterceptTouchEvent() would work for the sake of your purpose:

  • When touching parent at the position where its child is, the onInterceptTouchEvent() will be invoked, if we return false at ACTION_DOWN, it will be considered that parent did not steal this touch event yet, and check if its child was implemented onTouch(). Thus, as long as the child does not call requestDisallowInterceptTouchEvent(true), the parents still can handle this touch event in onInterceptTouchEvent() and the child can handle the same touch event in its own onTouch() event. However, sometimes you need to consider handling onTouch() event of the parents, in case there are no children handle the touch event, so the parents can take care of it.