I have a FiewFlipper that has ListViews as children. I have looked for a way to intercept touch events for a GestureDetector before they reach the children - a method to globally intercept touch events over the ViewFlipper.
Extending FiewFlipper and implementing onInterceptTouchEvent (MotionEvent ev) seemed to be the solution. This works well for most children. However, when the listview begins to scroll, onInterceptTouchEvent stop receiving the events.
I know it's possible to set each listview's OnTouchListener, but this ruins simple hierarchy I'm attempting to create.
Hmm. I once had an activity with a single listview, where I re-populated the adapter as a result of fling gestures. I did it by implementing the dispatchTouchEvent method of the activity:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return gestureDetector.onTouchEvent(ev);
}
The listview still received the normal events, but my gestureDectector got to taste them too. Perhaps a similar approach will work for you?
As commented by adamp, this behaviour is intentional and does not need to be fought. I applied the gesture listener to the children elements.
Related
Helle there,
I've been working with the CoordinateLayout inside i have nestedScrollview layout and it's childs.
It's similar to whats'app profile view. I have tried to mimic this ontouch and dispatchtouch event for more than two days without success.
I read lot about dispatchTouch event onTouchEvent, setOntouchListener. and it's related video's.
I read about Managing ViewGroup reference in android reference, but still it's confuses me. How to handle those touch events.In nestedScrollView i have child linearlayout and this layout contains lot of child views like button and edittext.
When i touch nestedScrollview (ActionDown) triggered and subsequently (ActionUp) started to scroll, but when i touch any of it's child's view it should wait for the movement of my finger and then start to call nestedScrollview if its a (ActionMove).
I've dealing this inside of AppCompatActivity.
How do i achieve this? Please help.
Thanks.
Stupid enough to play with what i don't understand.
I was able to mimic like whatsapp profile,
#Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
nestedScrollview.onTouchEvent(motionEvent);
return super.dispatchTouchEvent(motionEvent);
}
call actionMove on child view to consume the event. Voila this did that trick. How ever the Scroll was not smooth compared to the mimic :0
Call this child.setOnTouchListener
case MotionEvent.ACTION_MOVE:
if (zeroY < mTouchSlop) {
mIsScrolling = true;
Log.d(DEBUG_TAG, "general" + Float.toString(zeroY) + " " + Float.toString(plusY));
}
return true;
I was implementing the app tutorial which looks like this.
I made a nice and small ViewPager and placed it on the mock-up ImageView. The problem is that the ViewPager is not scrolled when I try to scroll it from elsewhere, say around the view pager indicators. This is so natural because there's no way that the ViewPager listens to touch event outside of itself.
How can I make ViewPager be scrolled when I try to scroll from elsewhere?
I've tried to detect touch events on the parent of the ViewPager but I couldn't figure out how to relate onFling() or onScroll() to ViewPager's scrolling.
If there's any better suggestion of implementing this kind of UI, what would be it?
Is there any tutorial or custom library similar to this?
set a View.OnTouchListener for your outer ViewPager and check inside if you are on proper page which is displaying inner ViewPager. if inner ViewPager isn't on its first or last you might dispatch MotionEvent to second dispatchTouchEvent(MotionEvent me)
outerViewPager.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if(outerViewPagerAdapter.isCurrentPageHaveInnerViewPager() &&
! innerViewPagerAdapter.isOnFirstOrLastPage()){
innerViewPagerAdapter.dispatchTouchEvent(event);
return true;
}
return super.onTouch(event); //outer will get touch events
}
});
you might also adjust x/y touch cords in event before dispatching if needed
I want to use a ListView (and have done this successfully before) containing custom Views.
Basically these custom views are vertical sliders, obviously conflicting with the natural behaviour of the ListView.
I fill it with my custom Views from an Adapter, and these react to the touches on the Items,
but once I move my finger more than a few pixels, it will scroll, and the custom View will not receive any touch-events anymore.
How can I (nicely) prevent the ListView from scrolling, when I touch my own components?
Can I somehow disable ListView Selection, and just forward the touches to the Items, but still use the scrolling behaviour?
Thank you in advance.
To prevent the scrolling of listview you can inplement on touch listener as follows
listView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_MOVE)
{
return true;
}
return false;
}
});
hope it will work and if it us useful to you give vote
You can intercept all touch events using onInterceptTouchEvent() in your root layout (one that contains the ListView, like a FrameLayout) as found here.
What you do there is capture the motion events (return true when a MotionEvent.ACTION_DOWN comes in), capture the following event in onTouchEvent(), decide whether the motion is meant for the list items or the list itself and accordingly dispatch the events.
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.
I tried to understand how Android handle touch event and got a little bit confused. From what I understand touch event are send to the root view and pass down to the children.
I have a FrameLayout that is a container for Fragment.
First fragment view is a ScrollView, second one is some kind of Gallery (HorizontalListView) and the last one is also FrameLayout. Only one fragment in the layout each time.
What I want to do is to identify user swipes on the screen, for the app use. I want to count the swipes and do something after some number of swipes.
I tried to put a OnTouchListener on the top FrameLayout but it doesn't get called when the child is the ScrollView or the Gallery. I tried to return false and also true in the end of onTouch, but I get same result - it's never being called.
How can I do it?
I just want to "transparently" handle the touch events and passing them on like I didn't even touch them.
My understanding is that it actually goes the other direction. The Child views get their event triggered first (sort of). The root view get's it's dispatchTouchEvent() called, which propagates the event down to the children's onTouchEvent(), and then, depending on whether they return true or false, the parent's onTouchEvent() is called.
The normal solution for intercepting things like this is to override dispatchTouchEvent(MotionEvent ev) in one's activity like so:
#Override
public boolean dispatchTouchEvent (MotionEvent ev) {
// Do your calcluations
return super.dispatchTouchEvent(ev);
}
The documentation for this one is here. Note that you can also override that method in any ViewGroup (such as a FrameLayout, etc)
I'm pretty new to Android app development, and I've been playing around with swipe gestures using Android's SimpleOnGestureListener and a ViewFlipper. There are 3 children of the ViewFlipper, and each is a ScrollView. They're all dynamically populated when the Activity loads, and they don't change after that. The ScrollView is where the SimpleOnGestureListeners are attached.
Here's the layout I'm using:
+ViewFlipper
++ScrollView (x3, one for each page, each with the following:)
+++LinearLayout (vertical)
++++TextView
++++TableLayout (dynamically populated w/TableRows)
++++View
I extended the onFling method with the common tutorial code you can find anywhere online, and it works great--except when one of the ScrollViews doesn't contain enough content to scroll.
I've narrowed the problem down to touch detection by overriding and calling super on every one of the SimpleOnGestureListener's methods to add a print-to-log.
When I swipe on a page that scrolls, I get something full of "in onClick" "in onScroll" "in onFling" etc. On a page that's too short to scroll, I get "in onClick" "in onShowPress" "in onLongPress", and that's only if I'm touching the content within the too-short scrollview's children--if I touch elsewhere I get no events at all.
Ideas on what's wrong, or how to detect the swipe gesture no matter how big the ScrollView is?
EDIT: I've determined that when I run this on an Android 2.2 emulator, as opposed to the Android 2.1u1 DroidX emulator I've been using, it goes away. This is reproducible across multiple environments.
I have some more insight on this; it seems as though onInterceptTouchEvent is not called for every motion event when a scrollview is contained within a flipper (or a WorkspaceView).
In particular, the behavior I found while modifying another view class to fix this very same issue (it is not unique to flippers) was as follows--note that this is Android 2.1 only:
If the scrollview is long enough to scroll, the ACTION_DOWN motion event is caught by the ScrollView, and every subsequent ACTION_MOVE event goes through onInterceptTouchEvent of the flipper, where it is intercepted and handled appropriately. In android 2.2, this behavior happens regardless of the scroll length.
Back to 2.1: If the scrollview is not long enough to scroll, the ACTION_DOWN motion event is not caught by the scrollview, but instead comes back to the onTouchEvent of the flipper. All subsequent ACTION_MOVE events of the same gesture skip the onInterceptTouchEvent function and go straight to the onTouchEvent function!
The way I resolved this was to take the functionality I had in onTouchEvent for ACTION_MOVE events and refactor it into its own method. In this way, I can have onTouchEvent call onInterceptTouchEvent followed by that functionality if it detects that the event has previously gone unhandled.
case MotionEvent.ACTION_MOVE:
if (touchState == TOUCH_STATE_SCROLLING) {
handleScrollMove(ev);
} else {
// Log.d("workspace","caught a move touch event but not scrolling");
//NOTE: We will never hit this case in Android 2.2. This is to fix a 2.1 bug.
//We need to do the work of interceptTouchEvent here because we don't intercept the move
//on children who don't scroll.
Log.d("workspace","handling move from onTouch");
if(onInterceptTouchEvent(ev) && touchState == TOUCH_STATE_SCROLLING){
handleScrollMove(ev);
}
}
break;
This is from WorkspaceView.java (a modification of Android's Workspace.java, found at the andro-views project on google code, and now here: Horizontal "tab"ish scroll between views ). In the case that we receive a move event, and we are scrolling (which only happens if we have deliberately chosen to intercept it--ie, it's set in the intercept function, so we've been to the intercept function already) we perform the move behavior we desire. If we receive a move event here and we are not scrolling, then we send the event back through onIntercept, and then see if we're now set to scrolling. If so, we perform the action.
It's not elegant, but it works!
I needed to create a new class that extended ScrollView, and used this:
#Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return gestureDetector.onTouchEvent(event);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
gestureDetector.onTouchEvent(ev);
super.dispatchTouchEvent(ev);
return true;
}
I have no idea why, but if I try to return anything but true in dispatchTouchEvent (the logical thing would have been to
return (gestureDetector.onTouchEvent(ev) || super.dispatchTouchEvent(ev));
if I understand properly), it doesn't work, and this does.
Try setting android:fillViewport="true" in your layout xml for each of the ScrollViews. That tells the ScrollView to be as large as the view it's contained in.
Had the same issue. You need to intercept the touch event on the children of the ScrollView when it's too short to have a scrollbar.