android – How to consume child view's touch event in parent view's touchlistener?-ThrowExceptions

Exception or error:

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.

How to solve:

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

###

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.

###

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.

###

It can be achieved by using “onInterceptTouchEvent”. Please try this,it may work

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
     onTouchEvent(ev);
     return  false;
}

Leave a Reply

Your email address will not be published. Required fields are marked *