Подтвердить что ты не робот

ViewPager обнаруживает, когда пользователь пытается вывести из пределов

Я использую ViewPager, состоящий из 6 страниц для отображения некоторых данных. Я хочу, чтобы иметь возможность вызвать метод, когда пользователь находится в позиции 0, и пытается пронести вправо (назад) или в позиции 5 и пытается пронестись влево (вперед), даже если для этих страниц не существует больше страниц направления. Есть ли способ прослушать эти сценарии?

4b9b3361

Ответ 1

Расширьте ViewPager и переопределите onInterceptTouchEvent() следующим образом:

public class CustomViewPager extends ViewPager {

    float mStartDragX;
    OnSwipeOutListener mListener;


    public void setOnSwipeOutListener(OnSwipeOutListener listener) {
        mListener = listener;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            if (mStartDragX < x && getCurrentItem() == 0) {
                mListener.onSwipeOutAtStart();
            } else if (mStartDragX > x && getCurrentItem() == getAdapter().getCount() - 1) {
                mListener.onSwipeOutAtEnd();
            }
            break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    public interface OnSwipeOutListener {
        public void onSwipeOutAtStart();
        public void onSwipeOutAtEnd();
    }

}

Ответ 2

Ответ от Флавио Фариа не работает для меня. Единственным событием, которое я получаю onInterceptTouchEvent(), является событие ACTION_DOWN. Поэтому я переопределяю метод onTouchEvent(), чтобы заставить его работать.

Вот код. Обратите внимание, что у меня есть только onSwipeOutAtEnd() в слушателе. Вы можете добавить свой код, чтобы поддерживать прокрутку влево на первом vier.

public class CustomViewPager extends ViewPager {

float mStartDragX;
OnSwipeOutListener mListener;


public void setOnSwipeOutListener(OnSwipeOutListener listener) {
    mListener = listener;
}

@Override
public boolean onTouchEvent(MotionEvent ev){
    if(getCurrentItem()==getAdapter().getCount()-1){
        final int action = ev.getAction();
        float x = ev.getX();
        switch(action & MotionEventCompat.ACTION_MASK){
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            if (x<mStartDragX){
                mListener.onSwipeOutAtEnd();
            }else{
                mStartDragX = 0;
            }
            break;
        }
    }else{
        mStartDragX=0;
    }
    return super.onTouchEvent(ev);
}    
public interface OnSwipeOutListener {
    public void onSwipeOutAtEnd();
}

Ответ 3

Как насчет установки OnPageChangeListener на вашем ViewPager? Затем вы можете изменить свои стрелки навигации или что угодно в onPageScrolled.

viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            updateNavigationArrows();
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }
});

Ответ 4

Большое спасибо @Flavio, хотя мне пришлось внести некоторые изменения в его код, потому что методы обратного вызова дважды стреляли, также я добавил код, чтобы проверить, есть ли зарегистрированный прослушиватель, чтобы избежать сбоя приложения, когда нет прослушивателя зарегистрировано. Это код, который я использовал, чтобы заставить его работать: с onSwipeOutAtStart и onSwipeOutAtEnd:

public class CustomViewPager extends android.support.v4.view.ViewPager {

    float mStartDragX;
    OnSwipeOutListener mOnSwipeOutListener;

    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setOnSwipeOutListener(OnSwipeOutListener listener) {
        mOnSwipeOutListener = listener;
    }

    private void onSwipeOutAtStart() {
        if (mOnSwipeOutListener!=null) {
            mOnSwipeOutListener.onSwipeOutAtStart();
        }
    }

    private void onSwipeOutAtEnd() {
        if (mOnSwipeOutListener!=null) {
            mOnSwipeOutListener.onSwipeOutAtEnd();
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch(ev.getAction() & MotionEventCompat.ACTION_MASK){
            case MotionEvent.ACTION_DOWN:
                mStartDragX = ev.getX();
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev){

        if(getCurrentItem()==0 || getCurrentItem()==getAdapter().getCount()-1){
            final int action = ev.getAction();
            float x = ev.getX();
            switch(action & MotionEventCompat.ACTION_MASK){
                case MotionEvent.ACTION_MOVE:
                    break;
                case MotionEvent.ACTION_UP:
                    if (getCurrentItem()==0 && x>mStartDragX) {
                        onSwipeOutAtStart();
                    }
                    if (getCurrentItem()==getAdapter().getCount()-1 && x<mStartDragX){
                        onSwipeOutAtEnd();
                    }
                    break;
            }
        }else{
            mStartDragX=0;
        }
        return super.onTouchEvent(ev);

    }

    public interface OnSwipeOutListener {
        void onSwipeOutAtStart();
        void onSwipeOutAtEnd();
    }
}

Ответ 5

Интересно, как это сработало для других, это не работает для меня.

onInterceptTouchEvent() принимает только событие ACTION_DOWN. Пока onTouchEvent() принимает только одно событие за раз: ACTION_DOWN, ACTION_UP и другие.

Мне пришлось переопределить как onInterceptTouchEvent(), так и onTouchEvent(), чтобы он работал правильно. ACTION_DOWN of onInterceptTouchEvent захватывает начальную точку X, а OnTouchEvent захватывает конечную точку X2. Который я сравнил его, чтобы определить направление движения.

Получить начальное значение X касания:

float x1 = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch(ev.getAction() & MotionEventCompat.ACTION_MASK){
        case MotionEvent.ACTION_DOWN:
            x1 = ev.getX();
            break;
        }
        return super.onInterceptTouchEvent(ev);
    }

Из кода tjlian616 onTouchEvent() прослушивает ACTION_UP и получает его последним X Значение. Пока я установил, что текущее значение элемента равно 0, чтобы получить салфетки в стартовом прослушивании. По сравнению с ним и добавьте активированный слушатель.

 @Override
 public boolean onTouchEvent(MotionEvent ev){
        if(getCurrentItem()==0){
            final int action = ev.getAction();
            switch(action & MotionEventCompat.ACTION_MASK){
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                mStartDragX = ev.getX();
                if (x1<mStartDragX){
                    Log.i("TOUCH: ", "ACTION UP " + x1 + " : " + mStartDragX );
                    mListener.onSwipeOutAtStart();
                }else{
                    Log.i("TOUCH ELSE : ", "ACTION UP " + x1 + " : " + mStartDragX );
                    mStartDragX = 0;
                }
                break;
            }
        }else{
            mStartDragX=0;
        }
        return super.onTouchEvent(ev);
    }