1

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'm_With_Stupid
  • 1,112
  • 4
  • 16
  • 35

1 Answers1

4

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.

    enter image description here

Required solution:

  • If the user is in first page and swipes right then list item should be swiped.

    enter image description here

  • If the user is in second page and swipes left then list item should be swiped.

    enter image description here

  • 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);
        }

    }
I'm_With_Stupid
  • 1,112
  • 4
  • 16
  • 35
Abhishek V
  • 12,488
  • 6
  • 51
  • 63
  • Thanks for the thorough answer. When i implement this, the touch event still gets picked up by the viewpager when i swipe right in fragment 0 and left in fragment 1. Did your code do that? – I'm_With_Stupid Sep 30 '14 at 12:02
  • @I'm_With_Stupid No. It was working fine. what happens if you swipe left in fragment 0? – Abhishek V Sep 30 '14 at 12:22
  • If i swipe left, it swipes to the next page. As it should, but when i swipe right the list item does not pick up the touch event, and the viewpager picks up the touch event. – I'm_With_Stupid Sep 30 '14 at 12:34
  • @I'm_With_Stupid So ListView does not pick up the touch event at all in both the directions? Which android version you are using? – Abhishek V Sep 30 '14 at 12:44
  • Running kitkat, and yes, listview does not pick up touch event in both directions. – I'm_With_Stupid Sep 30 '14 at 12:51
  • @I'm_With_Stupid Even I had used KitKat. In my case the ListView was always taking the touch so ViewPager was not swiping at all.After using the above code it was working fine. I will put my demo project in GitHub and will give you the link in some time. – Abhishek V Sep 30 '14 at 12:58
  • 1
    @I'm_With_Stupid I have shared the project here - https://github.com/vabhishek/EnhancedListViewDemo let me know if it is working – Abhishek V Sep 30 '14 at 16:09
  • nothing I do seems to make it work, do you want to see my projects code? – I'm_With_Stupid Oct 03 '14 at 05:26
  • @I'm_With_Stupid Sure..Is it possible to share it in GitHub? – Abhishek V Oct 03 '14 at 05:39
  • @I'm_With_Stupid The demo project which I shared earlier is working as you expected?? – Abhishek V Oct 03 '14 at 05:40
  • Here is the project on GitHub: [GitHub Link](https://github.com/theduffmaster/beacon_portal_android/commit/df1ccff4bf2d584b5e0f2fb15a8266827e4bf7c0) additionally, your project was perfect, exactly what I'm aiming for my project to do. – I'm_With_Stupid Oct 03 '14 at 19:21
  • Did you see anything in my code on github that could possible make it so my app behaves differently then yours? – I'm_With_Stupid Oct 05 '14 at 01:03
  • 1
    @I'm_With_Stupid It seems to me that the `SwipeRefreshLayout` is causing the problem. Can you remove the `SwipeRefreshLayout` once to to check if that is the problem? – Abhishek V Oct 05 '14 at 03:40
  • You were right, it was the swipe to refresh that was messing it up – I'm_With_Stupid Oct 05 '14 at 03:55
  • @I'm_With_Stupid Then you need to customize `SwipeRefreshLayout` too :D – Abhishek V Oct 05 '14 at 03:56
  • Yeah, i think thats what its gonna have to come to. Thanks for all the help, congrats you deserve the points. – I'm_With_Stupid Oct 05 '14 at 03:58
  • @I'm_With_Stupid Okay..Check this out http://stackoverflow.com/questions/24996604/enhancedlistview-swiperefreshlayout – Abhishek V Oct 05 '14 at 04:00
  • 1
    @I'm_With_Stupid I will try if I can customize SwipeRefreshLayout and will let you know if it works. – Abhishek V Oct 05 '14 at 04:01
  • WOW IT WORKS! only took you a second to fix it to. Thank You – I'm_With_Stupid Oct 05 '14 at 04:28
  • 1
    made an edit to fix some weird behavior when you were swiping it away, it works so perfect right now, its beautiful, thank you so much. – I'm_With_Stupid Oct 05 '14 at 04:35