Alright, this is giving me headache for over an hour. I've got several ScrollViews in ViewFlipper. I want to implement swipe left/right gesture while letting the scrollview to scroll. The idea is quite simple - intercept the event and viewflipper, parse it and pass it to the children no matter what happened. This way I can easily detect the swipe without making mess with the events.
Theoretically all I have to do is to handle onTouch or something like that and return false, so the event will be dispatched to children. But the Android is so smart he won't send my any other events than ACTION_DOWN if I return false, because it thinks I don't want them.
So how can I capture all the motion events coming to the ViewFlipper and it's children and still dispatch them to the children? I can handle detecting the swipe myself.
Android is very nasty about this kind of things. You have to subclass and implement dispatchTouchEvent the way you need. Or you can grab some android code and modify it. I tried to use onInterceptTouchEvent() but found it unusable.
check out onInterceptTouchEvent() for a view group, if you wish to analyze the touches on view flipper and return false to pass the actions to the child views. look at the following link for more information.
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
Related
I'm currently working on a project where I have a custom view (graph). It is located inside a RecyclerView which is inside a NestedScrollView. My GraphView has an onTouch event that allows to see additional info while you're dragging your finger over values. When I was initially trying to implement it I would frequently receive an ACTION_CANCEL which was due to parent view interfering with its scrolling. After that I found a hacky solution which was to disable the parent controls at all with requestDisallowInterceptTouchEvent(true).
But this solution isn't exactly what I'm looking for. Instead I would want my app to have both at the same time. So, basically, custom view would keep showing additional data and have its onTouchEvent() triggered but my RecyclerView or NestedScrollView would still be scrolling if it received a drag by y axis.
Is it possible to implement this kind of a behavior and what would I need to do exactly?
I have a ViewPager inside a custom pager. Both swipe in horizontal direction. As I understood the Android touch model, my custom pager should monitor touch events going through onInterceptTouchEvent, checking for a swipe gesture and intercepting when one is detected, but also respect requestDisallowInterceptTouchEvent so that if a child view should consume the same horizontal swipe gesture my custom view is monitoring for it is allowed to.
So far so good, my custom pager handles horizontal swipes well for non-scrolling or vertically scrolling child views and for horizontally scrolling child views, respects the disallow request so the child view can use the horizontal gesture.
However, if the horizontally scrolling child view has reached the end of its content so it cannot scroll any more, I would expect it to rescind its disallow request, so that the parent can intercept and consume the motion, but reading through the source (https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v4/java/android/support/v4/view/ViewPager.java, https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/ScrollView.java), I cannot see it ever calling requestDisallowInterceptTouchEvent with false argument, meaning once it has identified a gesture as a swipe, it will consume it regardless of whether it can actually make use of it or not.
Is my understanding of Android's touch handling system flawed, or are the standard view classes' touch handling too crude in this regard?
This is a question to improve my understanding of Android's touch handling model so I can work better with the system, not a request for workaround suggestions (though if the answer is authoritatively "the system does not allow for this", good workarounds are probably welcome to those who have a similar problem and find this question while searching)
Have you looked into ViewGroup.onNestedFling()?
The pertinent excerpt from its documentation:
If a nested scrolling child view would normally fling but it is at the edge of its own content, it can use this method to delegate the fling to its nested scrolling parent instead.
In an Android fragment, I have a GridLayout with views in it.
I would like to be able to detect when a user swipes over a view, even if he initially touches down outside of it. I've included a diagram to illustrate what I mean here :
Is there a simple way to do this (without using coordinates to see if the touch point is in the view)?
Thanks!
You solve this using View.OnTouchListeners.
Set OnTouchListeners both root view as well as your view.
Check for Events and actions ACTION_DOWN(touch event start),ACTION_UP(touch event over)
Set flags as per need for inside touch or outside touch.
basically you need capture events as well as points too.
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.
We are developing an application where we need to capture MotionEvents from multiple views simultaneously. When we try to do so, Android only dispatches events to the first touched view and, when touching another view simultaneously, it gives us an ACTION_POINTER_DOWN on the first view only, even if the pointer coordinates are outside its bounds and inside the other views'.
Is there any way we can get events dispatched to every touched view (in separate calls to OnTouch)?
We believe intercepting the touch events from a parent view and then manually dispatching them to each view might work, but even if it does, it would not be practical for what we are trying to achieve. Is there an easier way?
At least Android 3.0 adds support for splitting touch events between multiple Views.
Split touch events is enabled by default when AndroidManifest <uses-sdk> defines either android:minSdkVersion="11" or android:targetSdkVersion="11". For explanation See android:splitMotionEvents and android:windowEnableSplitTouch
Touch event is first catched by the view currently in focus. If you touched 1 view and have "consumed" event and are working with it, any other events will be dispatched to this view, no matter where you click.
If you return false from your touchListener (thus saying that event is not consumed) it will be delegated down to other views, but on another separate click new event will be dispatched to other view.
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-3-understanding-touch-events/1775
http://developer.android.com/guide/topics/ui/ui-events.html
While this should work automatically with Android SDK 11+, it wasn't working for my app. I was trying to capture touches in a main view, plus some views that were subviews of the main view; in that case, touches were only captured by the view "level" that received the first touch. I reorganized my view structure so that all the views were siblings and now they are capturing events as expected.