How to disable ListView touch events? Allow only childview clicks - android

I need to disable touchevent handling for a listview but allow it's children to receive clicks. I have a frame layout which has a mapview and the listview over it. When the list is empty, I want the map to handle all touch events but when the list is filled, I want the list items to receive clickevents.

You could intercept all touch events in a custom FrameLayout (your root ViewGroup) using onInterceptTouchEvent(): http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent).
What you do there is capture the MotionEvent.ACTION_DOWN event and decide whether the event is meant for the ListView or the MapView depending on whether the ListView is empty (touches go to the MapView) or filled and within the borders of the ListView (touches go to the ListView).
In both cases return true and capture the following ACTION_DOWN event in onTouchEvent() (still FrameLayout). That way all touch events up to ACTION_CANCEL will go to your FrameLayout's onTouchEvent().
Your FrameLayout's onTouchEvent() will dispatch all touch events either to the ListView or the MapView. The decision which views gets the events has been taken in onInterceptTouchEvent(), so you need to store the result of that decision somehow. That decision is valid between the ACTION_DOWN and the ACTION_POINTER_UP, ACTION_UP, ACTION_CANCEL events.
I'm not sure whether you want to disable all touch events for the non empty ListView that don't select a list item (flinging, scrolling etc.)? Because that would complicate matters considerably. Although I don't think that makes sense from a user perspective as list items not fitting the ListView's viewport could not be clicked because you can't scroll up or down.
Don't expect this to work easily. Understanding the flow of motion events and the interaction between onInterceptTouchEvent() and onTouchEvent() is challenging and making it work even more so. But I'm confident that this is a feasible way to solve your problem.

Related

Views in my ListView's items steal ACTION_DOWN event from it

I have ListView with complex items, that contain a few buttons and checkboxes (all of those buttons and checkboxes have their onClickListener's). Every item in listView might be deleted by dragging it to the left/right side. To make items draggable I override onTouchListener for ListView.
My problem is that when I try to drag an item or to scroll the ListView up/down, I don't receive ACTION_DOWN event in onTouch() method, but only when I start the action from the area of any of those Checkbox'es and Button's. So it looks like those elements steal my event. What I want to do, is to receive ACTION_DOWN, ACTION_MOVE, ACTION_UP events in onTouchListener of ListView, and then when ACTION_UP occurs check out whether I'm scrolling/dragging (which I have no problem with), and if I'm not, perform click either for some Button/Checkbox (if ACTION_DOWN started from its area) or for an item (if ACTION_DOWN started from some area that doesn't belong to any of buttons/checkboxes).
Please check this SwipeMenuLib library. It may be useful for you

Analyzing touch events in a child view and let the parent handle them if condition not satisfied

I have extended a FrameLayout and overriden the onInterceptTouchEvent() and onTouchEvent(). This custom Framelayout will be the root layout of my ListView rows.
My requirement is that, if I tap on a row in the ListView, the onItemClickListener should be called, if I scroll (up/down) the list scrolls as usual. However if I scroll (left/right) or swipe (left/right), the custom FrameLayout should take some action based upon which row I perform the action on.
My idea was that, I would override onInterceptTouchEvent, monitor the events and if I see that ACTION_MOVE has been called enough to make it a scroll/swipe then I take control and do the task. If it's a tap or some other gesture then let the default flow occur.
The problem I face now is that if my framelayout does not contain any touchable child, then I receive no calls post ACTION_DOWN. And if I receive the ACTION_DOWN in my onTouchEvent() so as to analyze the kind of gesture, then I have no control left to let the default flow occur if I calculate and find that the action was actually just a tap/vertical scroll.
Is there some way in which a child can get hold of the events (ACTION_DOWN and ACTION_MOVE) and if a condition satisfies then perform an action or else let the parent handle these same events?
Is there some other approach that I can take to satisfy this requirement?

How to support native ListView item click while having scrollable ListItem

Problem
While developing some kind of "Contextual actions" for ListView item on swipe gesture I have been a little bit confused about the way Android dispatches MotionEvents to ViewGroup's children.
According to documentation all the things start with ViewGroupd.dispatchTouchEvent(MotionEvent) method call. Then view group ask whether the particular motion event should be intercepted or we can dispatch it to our childrens. This works great with all kinds of scrolling so we can efficiently resolve conflicts between vertical and horizontal scrolling (for example ListView inside ViewPager).
However I can't successfully handle simple click event in list view this way.
Motion events dispatching trace looks like this
ListView.dispatchTouchEvent(DOWN)
ListView.onInterceptTouchEvent(DOWN) returns false;
QuickActionView.dispatchTouchEvent(DOWN)
QuickActionView.onTouchEvent(DOWN) return true because MotionEvent.ACTION_DOWN indicates about start of gesture and it possibly can be horizontal scroll and we should appear quick actions layout to the user in this case. If we return false from here on MotionEvent.ACTION_DOWN it prevents from other touch events to be dispatched to this child of ListView.
Due to step 4 QuickActionView.dispatchTouchEvent(DOWN) return true
Due to step 5 ListView.dispatchTouchEvent(DOWN) return true
As a result ListView remember touch target. So next message dispatched like this.
ListView.dispatchTouchEvent(UP)
ListView.onInterceptTouchEvent(UP) returns false;
QuickActionView.dispatchTouchEvent(UP)
QuickActionView.onTouchEvent(UP) return false because we now see that the gesture is over and it isn't scroll or fling or whatever.
Due to step 4 QuickActionView.dispatchTouchEvent(UP) return false
Due to step 5 ListView.dispatchTouchEvent(UP) return false
So there is no chance for ListView to handle item click because after step 5 with UP action the motion event doesn't directed to the ListView's onTouchEvent(MotionEvent) method.
I have also tried to "intercept" touch event with ACTION_UP inside ListView, but have noticed that according to Android documentation after interception only further motion events will be directed to the ViewGroup's onTouchEvent(MotionEvent) method, and the current one won't.
Question
How can I support both the ListView's native item click handling and ability to dispatch MotionEvents to ListItem view (it is horizontal scrollable and have image buttons)?
It is preferred to hear from someone experienced in such a problem solving or have deeper understanding about how it designed to work with specified conflict solving
At the moment I have two solutions to this problem
Divide QuickActionView (which is actually ListView item) into two sections:
____________________
| clickable | |
|________________|__|
^
|
scrollable
So that I can't scroll ListView item in case the initial ACTION_DOWN motion event starts from clickable area, but list view handles item clicking natively. And I can't click list item inside scrollable area, whereas I can scroll to appear quick actions if my gesture starts from scrollable area.
The second solution is rather hacky but avoids limitations of the first one
Inside ListView I can remember all the touch events via MotionEvent.obtain(MotionEvent) method. Then I wait for the ACTION_UP MotionEvent and ask the listItem view whether the gesture has been processed or not. If list item tells that the gesture has NOT been processed I then call private method ListView.cancelTouchTarget() and post all saved MotionEvents to the listView via super.dispatchTouchEvent(MotionEvent)

How to add touch event for a Layout that contains a ScrollView

The problem is the the scrolling will intercept with touch event has set to the parent layout.
Can I keep the onTouch event with the scroll in ScrollView ?
This is a very tricky part. There is an overriden method from Activity which is: public boolean onTouchEvent(MotionEvent event)
This is the general method that interprets all the touch events from the whole screen. And you could say, "ok, I can implement this and I am good to go..". And here comes the difficult part on how android works.
As you know every View has its own onTouchEvent() method that you could implement in order to add some custom implementation. So which method will listen? The ScrollView or the Activity? It appears that these touch events go from the "inside" elements to the "outside" elements. I mean parent-child relations.
Another thing to take into account is that the onTouchEvent method returns a boolean. This boolean parameter determines whether the touch event should go one level up or it is handled by the current View. Meaning that if you have a CustomViewA that implements the onTouchEvent() and CustomViewB implementing its own touch event, and the A is a child in B then the touch event would go through A first and if it is not handled it would go to B.
So basically yes it could be done. It depends on what touch event you wanted to do.
So in our case, the ScrollView returns true when the touch events are a horizontal. The activity's touch event will be handled only if the ScrollView touch event is not handled by itself then you are fine. Otherwise you have to override and implement the on touch event of scroll view and in some cases you have to return false so as for the whole layout to implement it. Good luck with the last part. I started to implement a fling effect but came up with some difficulties so I have implemented a 2 finger move with scroll view in it and it works like a charm.
This is about a week of research and experimenting and it is an overview of what I came up with. if you find anything else please let me know. Hope it helped.

process touch events across multiple scrollviews

I have two scrollviews side by side, I want the user to be able to drag list items back and forth from left to right scrollviews. However, I can't find a way to handle the touch events. I can't set a touch listener for each scrollview seperately as the drag gesture gets dropped when passing from one to another. I tried creating an absolute layout over the top of both, which works from the drag and drop perspective, but it stops me from being able to scroll the scrollviews. Is there a simple solution to this? can anyone help me out?
Generally, onTouchListener returns a boolean that indicates whether the touch has been handled. It's up to you to decide whether the touch was handled or not. When the user touches a View, Android will call it's touch listener. If the touch listener returns true, then it regards the touch as handled then moves on. If the touch listener returns false, then it will go up one to the parent view (in this case whatever your ScrollView is). Then the parent view's touch listener is called and must decide how to handle the touch. It will keep cascading up the parent views until a true is returned or until it reaches the end.
In your case, you may have to decide what the user has to do in order to drag & drop vs. scrolling. Perhaps the user must do a long press on an item before he/she can drag it or something.

Categories

Resources