I have a ViewPager that contains two fragments, which each contains listviews with swipeable list items. To make it easier for the user to swipe, I would like it so that if the user swipes left in the first fragment, the swipe is picked up by the listview. If the user swipes right in the second fragment, the swipe is picked up by the listview. Since there is only two fragments, it makes sense for the swipes to be picked up by the listview, and not the viewpager since there are no more fragments to scroll to after these two.
So, would it be possible to intercept the touch, and pass it to the listview based on the viewpager page being shown the and the direction of the swipe?
Here is the swipable listview library I am using: https://github.com/timroes/EnhancedListView
I think you can customize the ViewPager
and control the behavior of ListView
swipe in canScroll
method of the ViewPager
.
I tried a sample and it seems to be working fine. You can use this Custom ViewPager
.
public class CustomViewPager extends ViewPager {
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewPager) {
if (getChildAt(getCurrentItem()) != null) {
//get the ListView of current Fragment
EnhancedListView enhancedListView = (EnhancedListView) getChildAt(getCurrentItem()).findViewById(R.id.list);
//If the user is in first page and tries to swipe left, enable the ListView swipe
if (getCurrentItem() == 0 && dx > 0) {
enhancedListView.enableSwipeToDismiss();
}
//If the user is in second page and tries to swipe right, enable the ListView swipe
else if (getCurrentItem() == 1 && dx < 0) {
enhancedListView.enableSwipeToDismiss();
}
//Block the ListView swipe there by enabling the parent ViewPager swiping
else {
enhancedListView.disableSwipeToDismiss();
}
}
}
return super.canScroll(v, checkV, dx, x, y);
}
}
Also you have to do some changes in EnhancedListView
library as well. Because canScroll
method is called after ACTION_DOWN
event, if we enable the swiping in canScroll
method - it skips the logic defined forACTION_DOWN
event and it might results in unexpected behavior. So block the swipe only if touch event is ACTION_MOVE
. These are the changes in onTouchEvent
of EnhancedListView
library.
//EnhancedListView class
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!mSwipeEnabled && (ev.getAction() == MotionEvent.ACTION_MOVE)) {
return super.onTouchEvent(ev);
}
.....
I am not sure if this is the perfect solution for the problem but it is working just fine.
Here are some screenshots of the sample app if the question or the answer is not clear.
App consists of ViewPager
with two Fragment pages. Each page has an EnhanedListView (Which provides Swipe To Dismiss/Delete feature). Since both parent ViewPager
and child List item can be swiped, it causes a conflict. By default swipe is picked up by the child ListItem which prevents the parent ViewPager
from swiping.
Required solution:
If the user is in first page and swipes right then list item should be swiped.
If the user is in second page and swipes left then list item should be swiped.
In other cases the ViewPager
should be swiped.
update : To fix the bug with SwipeRefreshLayout
, here are the slight changes in custom ViewPager
code.
public class ScrollLock extends ViewPager {
public ScrollLock(Context context) {
super(context);
}
public ScrollLock(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewPager) {
if (getChildAt(getCurrentItem()) != null) {
//set it so it does not swipe to refresh while swiping away a list item
SwipeRefreshLayout swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe);
//get the ListView of current Fragment
EnhancedListView enhancedListView = (EnhancedListView) getChildAt(getCurrentItem()).findViewById(R.id.listView1);
//If the user is in first page and tries to swipe left, enable the ListView swipe
if (getCurrentItem() == 0 && dx > 0) {
enhancedListView.enableSwipeToDismiss();
swipeLayout.setEnabled(false);
return true;
}
//If the user is in second page and tries to swipe right, enable the ListView swipe
else if (getCurrentItem() == 1 && dx < 0) {
enhancedListView.enableSwipeToDismiss();
swipeLayout.setEnabled(false);
return true;
}
//Block the ListView swipe there by enabling the parent ViewPager swiping
else {
enhancedListView.disableSwipeToDismiss();
}
}
}
return super.canScroll(v, checkV, dx, x, y);
}
}