How to consume child view's touch event in parent view's touchlistener?

30,945

Solution 1

You could accomplish that by overriding dispatchTouchEvent in the layout.

public class MyFrameLayout extends FrameLayout {
    @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. If you need to recreate some, but not all, of the default functionality, there is a lot to rewrite:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/view/ViewGroup.java#ViewGroup.dispatchTouchEvent%28android.view.MotionEvent%29

Solution 2

I have tried similar design with (only one onTouch Listener on a root FrameLayout) and it worked. I get all the points provided that onTouch return true instead of false. Otherwise, I just get the first point. I couldn't find out the reason for this "return" issue since I expect opposite behaviour.

However, based on my experience, if you set any of child view clickable, then its parent's onTouch will not work. If you have another solution and if you share, that would be great.

Solution 3

2 solutions:

  1. Use onInterceptTouchEvent on the ViewGroup, as shown here

  2. Avoid having the layout handle the touch events, and have a view that is the child view of the layout, that covers its whole size, to handle the touch events.

    It's not as efficient as extending classes, but it is much easier and doesn't require to create new files/classes.

    example:

    Just add the touch events to the view, and it will handle them instead of any of the other views.

Share:
30,945
Sock
Author by

Sock

Updated on November 04, 2020

Comments

  • Sock
    Sock over 3 years

    In my application I want to get the touch event of all child view's in my parent view's onTouchListener but I could not get this.

    Example:

    In my activity's view I have one frame layout which has some buttons and edittexts in it. So whenever I touch buttons or edit text I want to get this touch event in framlayout's onTouchListeners.

    Here is my code..

    Activity:

    private FrameLayout rootView;
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            rootView = (FrameLayout) findViewById(R.id.rootview);
            rootView.setOnTouchListener(new OnTouchListener()
            {
                @Override
                public boolean onTouch(View v, MotionEvent event)
                {
                    Log.e("Touch Event: ", " X: " + event.getX() + " Y: " + event.getY());
                    return false;
                }
            });
             }
    

    main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout 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">
    
    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="vertical"
        android:layout_gravity="center" 
        android:padding="10dip">
    
         <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:padding="4dp"
                        android:text="Login"
                        android:textColor="@android:color/black"
                        android:textSize="16dp"
                        android:textStyle="bold" />
    
                    <TextView
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="10dp"
                        android:text="Username"
                        android:textColor="@android:color/black"
                        android:textSize="14dp"
                        android:textStyle="bold" />
    
                    <EditText
                        android:id="@+id/edttextusername"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:imeOptions="flagNoExtractUi"
                        android:singleLine="true" />
    
                    <TextView
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="10dp"
                        android:text="Password"
                        android:textColor="@android:color/black"
                        android:textSize="14dp"
                        android:textStyle="bold" />
    
                    <EditText
                        android:id="@+id/edttextpassword"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:imeOptions="flagNoExtractUi"
                        android:password="true" />
    
                    <LinearLayout
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:gravity="center"
                        android:orientation="horizontal"
                        android:padding="10dp" >
    
                        <Button
                            android:id="@+id/btnlogin"
                            android:layout_width="0dip"
                            android:layout_height="40dip"
                            android:layout_marginRight="5dp"
                            android:layout_weight="1"
                            android:enabled="false"
                            android:text="Login"
                            android:padding="5dip"
                            android:textColor="@android:color/black"
                            android:textStyle="bold" 
                            />
    
                        <Button
                            android:id="@+id/btncall"
                            android:layout_width="0dip"
                            android:layout_height="40dip"
                            android:layout_marginLeft="5dp"
                            android:layout_weight="1"
                            android:padding="5dip"
                            android:text="Cancel"
                            android:textColor="@android:color/black"
                            android:textStyle="bold" />
                    </LinearLayout>
    
    
    </LinearLayout>
    
        </FrameLayout> 
    

    Problem: So whenver I touch the buttons or edittext I can't get touch co-ordition in my frame layout's onTouchListener (It's not called).

    Note: I don't want to add separate onTouchListener for all childViews.

    Thanks in advance.