4

I have a list view whose item is a linearlayout which has a button as it's child view. I want the ontouchLIstener of the linearlayout to work. I don't want to use onInterceptTouchEvent. Is there a way a I can pass on the touch form the button to the parent listview. I tried this - returning true from the button's onTouchListener

private View.OnTouchListener buttonListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.i(TAG, "Button On Touch");
            return true;
        }
};

But this does not work. It does not pass on the touch event to the linearlayout's onTouchListener.

There must be someway it should work.

Ziem
  • 6,579
  • 8
  • 53
  • 86
Ashwin
  • 12,691
  • 31
  • 118
  • 190
  • try returning false instead – Evan Aug 24 '14 at 19:58
  • @Evan : Nope, doesn't work still. The logs in the parent's onTouchListener show nothing. – Ashwin Aug 24 '14 at 20:01
  • 1
    you will have to use onInterceptTouchEvent, this is what it is for – pskink Aug 24 '14 at 20:02
  • @pskink : The problem with using onInterceptTou.. is that I will have to use a custom layout that extends linearlayout. And also I want the code to reside in the listadaper class which is not possible with onINtercept... since it can only be overriden. Is it possible to pass the touch event from OnInterceptTouchEvent to OnTouchListener? – Ashwin Aug 24 '14 at 20:06

2 Answers2

11

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

Community
  • 1
  • 1
Ashwin
  • 12,691
  • 31
  • 118
  • 190
3

Set your button clickable property to false, using:

button.setClickable(false);

Then in onTouch of button:

return false;

Note: This behavior is specific to button (and any other view that has clickable property set to true) that even if you return false from onTouch it will not propagate event to the parent and onClick method of the button will be called anyway.


EDIT: Another way is extending ListView class and overriding onInterceptTouch:

public class CustomListView extends ListView {
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // here you can listen for button touch events
    }
}
semsamot
  • 805
  • 9
  • 11
  • But I want the button to be clickable. – Ashwin Aug 24 '14 at 20:09
  • : What do you mean by "this behavior is specific to button"? Will it not happen for other views? – Ashwin Aug 25 '14 at 01:19
  • Specific to button because it's clickable as default. Any other view that has `clickable` property set to `true` will behave as same as button. (I edited again to clarify) – semsamot Aug 25 '14 at 13:11