ViewPager inside ViewPager
override canScroll in the parent ViewPager:
@Overrideprotected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v != this && v instanceof ViewPager) { return true; } return super.canScroll(v, checkV, dx, x, y);}
Try this:
public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { ViewPager pager = (ViewPager)findViewById(childId); if (pager != null) { pager.requestDisallowInterceptTouchEvent(true); } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; }}
I searched a long time to make a ViewPager inside another ViewPager work and found the solution by "Android Noob" here. Thank you very much for that!
I wanted to share my solution, too. I added the possibility to switch the swipe management to the surrounding ViewPager once the last (most right) element in the inner ViewPager is reached. To prevent glitches, i also save the first swipe direction for the last elemen: i.e. if you swipe left first, a minimal right swipe doesnt reset the scroll state.
public class GalleryViewPager extends ViewPager { /** the last x position */ private float lastX; /** if the first swipe was from left to right (->), dont listen to swipes from the right */ private boolean slidingLeft; /** if the first swipe was from right to left (<-), dont listen to swipes from the left */ private boolean slidingRight; public GalleryViewPager(final Context context, final AttributeSet attrs) { super(context, attrs); } public GalleryViewPager(final Context context) { super(context); } @Override public boolean onTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow parent ViewPager to intercept touch events. this.getParent().requestDisallowInterceptTouchEvent(true); // save the current x position this.lastX = ev.getX(); break; case MotionEvent.ACTION_UP: // Allow parent ViewPager to intercept touch events. this.getParent().requestDisallowInterceptTouchEvent(false); // save the current x position this.lastX = ev.getX(); // reset swipe actions this.slidingLeft = false; this.slidingRight = false; break; case MotionEvent.ACTION_MOVE: /* * if this is the first item, scrolling from left to * right should navigate in the surrounding ViewPager */ if (this.getCurrentItem() == 0) { // swiping from left to right (->)? if (this.lastX <= ev.getX() && !this.slidingRight) { // make the parent touch interception active -> parent pager can swipe this.getParent().requestDisallowInterceptTouchEvent(false); } else { /* * if the first swipe was from right to left, dont listen to swipes * from left to right. this fixes glitches where the user first swipes * right, then left and the scrolling state gets reset */ this.slidingRight = true; // save the current x position this.lastX = ev.getX(); this.getParent().requestDisallowInterceptTouchEvent(true); } } else /* * if this is the last item, scrolling from right to * left should navigate in the surrounding ViewPager */ if (this.getCurrentItem() == this.getAdapter().getCount() - 1) { // swiping from right to left (<-)? if (this.lastX >= ev.getX() && !this.slidingLeft) { // make the parent touch interception active -> parent pager can swipe this.getParent().requestDisallowInterceptTouchEvent(false); } else { /* * if the first swipe was from left to right, dont listen to swipes * from right to left. this fixes glitches where the user first swipes * left, then right and the scrolling state gets reset */ this.slidingLeft = true; // save the current x position this.lastX = ev.getX(); this.getParent().requestDisallowInterceptTouchEvent(true); } } break; } super.onTouchEvent(ev); return true; }}
Hope this helps someone in the future!