Detect swiping out of bounds in Android's ViewPager2

1.5k views Asked by At

I'm using ViewPager2 and want to detect when the user swipes either to the left on the first page or the right on the last page.

I know this can be implemented using the old ViewPager like discussed here, but this approach is not feasible since ViewPager2 is final and can't be subclassed.

ViewPager2 provides the OnPageChangeCallback but this can't be used either since there are no page events when swiping out of bounds.

Am I missing something?

2

There are 2 answers

0
flauschtrud On BEST ANSWER

I figured out a (slighly hacky) solution while I was typing this question.

It is based on the observation that the state SCROLL_STATE_SETTLING is only reached when the viewpager really settles on a new page. If there is only fruitless dragging on the first or last page then only the states SCROLL_STATE_DRAGGING and finally SCROLL_STATE_IDLE are passed.

viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

        private boolean settled = false;

        @Override
        public void onPageScrollStateChanged(int state) {
            super.onPageScrollStateChanged(state);
            if (state == SCROLL_STATE_DRAGGING) {
                settled = false;
            }
            if (state == SCROLL_STATE_SETTLING) {
                settled = true;
            }
            if (state == SCROLL_STATE_IDLE && !settled) {
                doYourOutOfBoundsStuff();
            }
        }
    });

I'm not entirely happy, but this is the best I came across so far.

0
Reza Zavareh On

thanks, @flauschtrud To handle better swapping right on the last index or swapping left to the first index of your child tab layout, I use this code for a challenge when I wanted to change paging on nested tab layouts because SwipeChangeListener could not detect swap to the left & right when you were on the first index or the last index of the tab layout item

yourChildViewPager.registerOnPageChangeCallback(object :
            OnPageChangeCallback() {
            private var settled = false
            override fun onPageScrollStateChanged(state: Int) {
                super.onPageScrollStateChanged(state)
                if (state == SCROLL_STATE_DRAGGING) {
                    settled = false
                }
                if (state == SCROLL_STATE_SETTLING) {
                    settled = true
                }
                if (state == SCROLL_STATE_IDLE && !settled) {
                    if (yourChildViewPager.currentItem == 0) {
                        backDirectionToParentViewPager()
                    } else {
                        forwardDirectionToParentViewPager()
                    }
                }
            }
        })

Note: You can handle disable or enable paging in your parent view pager (ViewPager2) with this code:

   yourParentViewPager.isUserInputEnabled = (true or false)