Control which directions the ViewPager can be scrolled, dynamically with UI feedback

后端 未结 5 489
既然无缘
既然无缘 2020-12-13 22:40

I\'m working on an app which uses many pages to swipe through, however at some pages I would like to be able to prevent scrolling to the next page until they\'ve selected so

相关标签:
5条回答
  • 2020-12-13 23:12

    I have been googling high and low for a good way to solving this problem... I tried overriding ontouchevent etc...

    I decided this was the best solution for me (and less hacky).. was just to implement a maximum or minimum tracker and set it to current page

            maxPageToScroll = viewPager.getCurrentItem();
            minPageToScroll = viewPager.getCurrentItem();
    

    and then add to "onPageSelected" method:

    public void onPageSelected(int position) {
    
            if (position < minPageToScroll) {
                viewPager.setCurrentItem(maxPageToScroll);
            }
            else if (position > maxPageToScroll) {
                viewPager.setCurrentItem(maxPageToScroll);
                // you can alert here that user needs to do certain actions before proceeding
            }
            else { 
                // enter normal commands here
            }
    

    consequently, when conditions are met you simply increase the maxpage by one..

            maxPageToScroll = viewPager.getCurrentItem() + 1;
    

    note that this doesn't prevent user form scrolling... it just prevents view pager from changing pages.

    0 讨论(0)
  • 2020-12-13 23:13

    I don't think extending ViewPager is needed. What you need to do is to modify the list of pages provided to the PagerAdapter on the fly. Meaning that, you check if a certain page is marked "completed" and only then add the next page to the list. That's how ViewPager works.

    Take a look at Roman Nurik's wizard-pager implementation. In MainActivity there is a method called recalculateCutOffPage which does what I said.

    0 讨论(0)
  • 2020-12-13 23:21

    I implmented viewpager for a wizard with a max page that the user can't pass it.

    At the end the solution was in the adapter. I changed the count of the PagerAdapter and this way blocks the user from passing the max page:

    @Override
    public int getCount() {
        return mProgress; //max page + 1
    }
    

    When the user progresses to the next page:

    private void setWizardProgress(int progress) {
        if(progress > mProgress) {
            mProgress = progress;
            mWizardPagerAdapter.notifyDataSetChanged();
        }
    }
    

    This way when the user is at max page he can't scroll to the right until the progress is updated.

    0 讨论(0)
  • 2020-12-13 23:27

    When I faced a similar problem, I made my own Listener with a gestureDetector and made it not respond to swiping at all, you can easily adjust it to not respond to swiping to the right only under some condition. This should answer your numbers 1 and 2.

    This is the listener:

    public class OnSwipeTouchListener implements OnTouchListener {
    
    @SuppressWarnings("deprecation")
    private final GestureDetector gestureDetector = new GestureDetector(new GestureListener());
    
    public boolean onTouch(final View v, final MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }
    
    private final class GestureListener extends SimpleOnGestureListener {
    
        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;
    
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            onTouch(e);
            return true;
        }
    
    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            onSwipeRight();
                        } else {
                            onSwipeLeft();
                        }
                    }
                } else {
                   // onTouch(e);
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }
    public void onTouch(MotionEvent e) {
    }
    public void onSwipeRight() {
    //call this only if your condition was set
    }
    
    public void onSwipeLeft() {
    //nothing, this means,swipes to left will be ignored
    }
    
    public void onSwipeTop() {
    }
    
    public void onSwipeBottom() {
    }
    }
    

    and this is an example of use :

    viewPager.setOnTouchListener(new OnSwipeTouchListener() {
    public void onSwipeRight() {
      if(your conditionIsMet){
    // move your pager view to the right
         }
       }
    
    });
    

    There might be a simpler and more elegant solution, but this worked well for me.

    0 讨论(0)
  • 2020-12-13 23:30

    you can use your custom view pager

    public class CustomViewPager extends ViewPager
    {   
    float mStartDragX;
    OnSwipeOutListener mListener;
    Context context;
    public static boolean enabled;
    
    public CustomViewPager(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        this.context = context;
        enabled = true;
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
    
        if (enabled) //view pager scrolling enable if true
        {
            return super.onTouchEvent(event);
        }
        return false;
    }
    
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
    
        if (enabled)enter code here
        {
            return super.onInterceptTouchEvent(ev);
        }
        else  // view pager disable scrolling 
        {
            float x = ev.getX();
            switch (ev.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                    mStartDragX = x;
    
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mStartDragX < x - 100)//100 value velocity
                    {
                        //Left scroll 
                        //return super.onInterceptTouchEvent(ev); 
                    }
                    else
                        if (mStartDragX > x + 100)
                        {
                            //Right scroll 
                            //return super.onInterceptTouchEvent(ev);
                        }
                    break;
            }
        }
    
        return false;
    
    }
    
    
    public void setOnSwipeOutListener(OnSwipeOutListener listener)
    {
        mListener = listener;
    }
    
    public interface OnSwipeOutListener
    {
    
        public void onSwipeOutAtStart();
    
    
        public void onSwipeOutAtEnd();
    }
    

    }

    0 讨论(0)
提交回复
热议问题