I recently changed the ViewPager in my application to a ViewPager2. I had set an onTouchListener to the viewPager object to detect gestures (onFling and onLongPress), as such:
mViewPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mDetector.onTouchEvent(motionEvent); // use the custom gesture detector to detect onFling and onLongPress touch events.
return true;
}
});
The onTouchListener for the viewPager was working fine before the refactor to the ViewPager2. I tried this answer, but it didn't work.
Anyone has an idea as to why this might be the case and how I could fix it?
Because ViewPager2 is a ViewGroup, the final target is the recyclerview in it. The setOnTouchListener is not called because the recyclerview intercepts the event and calls the onTouchEvent first.
The right way to add customised onTouch logic is to call
mViewPager.getChildAt(0).setOnTouchListener{...}
The right way to add customised onTouch logic is to call
viewPager2.getChildAt(viewPager2.getCurrentItem()).setOnTouchListener(...)
Related
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 have a listview inside a RelativeLayout. I want any clicks on the listview to call the Relativelayout's onClick listener. How can the listview pass it's click events to the parent view.
I tried this not working.
listView.setOnTouchListener(new OnTouchListener() {
// Setting on Touch Listener for handling the touch inside
// ScrollView
#Override
public boolean onTouch(View v, MotionEvent event) {
// Disallow the touch request for parent scroll on touch of
// child view
listView.requestDisallowInterceptTouchEvent(false);
return false;
}
});
I think you need to use one of those methods in order to be able to intercept the event before it gets sent to the appropriate components:
Activity.dispatchTouchEvent(MotionEvent) - This allows your Activity to intercept all touch events before they are dispatched to the window.
ViewGroup.onInterceptTouchEvent(MotionEvent) - This allows a ViewGroup to watch events as they are dispatched to child Views.
ViewParent.requestDisallowInterceptTouchEvent(boolean) - Call this upon a parent View to indicate that it should not intercept touch events with onInterceptTouchEvent(MotionEvent).'
for reference please check here EventHandlers
Can use in XML:
android:focusable="false"
In java code use:
v.setClickable(false)
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.
Scope
There is a viewpager of two fragments. One of those fragments has a layout witch listens to onTouch changes at X-axis.
Problem
Layout doesn't get almost all Action.Move events when touching and sliding along X-axis.
It seems that viewpager has a onInterceptTouchEvent which returns true.
Question
Is it real to override viewpager's behavior to make it and my layout work together? So the perfect situation is layout intercepts all onTouch events on it and viewpager manages the rest of onTouch events. Thanks!
You are right, I believe every scrolling container intercepts touch events, but you can prevent it. You can put a touch listener on your layout:
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
pager.requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
pager.requestDisallowInterceptTouchEvent(false);
break;
}
}
Similar situation (but not using a ViewPager), putting this in the view that needed the touch event worked for me. Add checks for MotionEvents other than ACTION_MOVE if applicable to your use case.
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
this.getParent().requestDisallowInterceptTouchEvent(true);
return true;
} else {
return super.onTouchEvent(event);
}
}
neutrino was right!
getParent().requestDisallowInterceptTouchEvent(true);
once the viewpager access the touchEvent Intercept,the child view in it can got the event.
enter image description here
I use a FrameLayout in viewpager to got the DrawerLayout Effect(I need it not match the height of screen,so I can't use drawerlayout or navigation drawer).
It really helps!
I had a similar problem.
In my case I was setting a OnTouchListener on ViewPager but it wasn't receiving touch events when the children that received the touch had onClick set.
What I did was extend the ViewPager class and call my click listener inside the method onInterceptTouchEvent(boolean) and it worked fine. Just be careful not to intercept wrong events.
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.