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

Дифференциация между прокруткой и изменением страницы программы в ViewPager

У меня есть android.support.v4.view.ViewPager в моем приложении, и я хотел бы провести различие между программно-инициированным гладким прокруткой и инициированным пользователем сенсорным прокруткой.

Я посмотрел на ViewPager.OnPageChangeListener, и я считаю, что ответ может лежать там, но я просто не уверен, как это сделать.

4b9b3361

Ответ 1

Хорошо, так получается, что я был прав насчет ответа, лежащего в ViewPager.onPageChangeListener. В частности, она заключается в использовании onPageScrollStateChanged(int state). По существу, есть три состояния, что страница в ViewPager может находиться в:

  • Перетаскивание: указывает, что пейджер в настоящее время перетаскивается пользователем.
  • Idle: указывает, что пейджер находится в состоянии ожидания, опустившемся состоянии.
  • Settling: указывает, что пейджер находится в процессе установки в конечную позицию.

Таким образом, состояние перетаскивания происходит только тогда, когда текущая страница физически перетаскивается пользователем. Таким образом, когда пользователь проведет страницу, состояния будут выполняться в следующем порядке: Перетаскивание → Урегулирование → Простой. Теперь метод onPageSelected(int position) вызывается между состояниями "Settling" и "Idle". Таким образом, чтобы определить, было ли изменение страницы вызвано прокруткой пользователя, нужно просто проверить, что предыдущее состояние было "перетаскиванием", и что текущее состояние "Устанавливается". Затем вы можете сохранить переменную boolean, чтобы отслеживать, было ли изменение страницы пользователем инициировано или нет, и проверьте его в методе onPageSelected(int position).

Вот мой метод onPageScrollStateChanged

public void onPageScrollStateChanged(int state) 
{
    if (previousState == ViewPager.SCROLL_STATE_DRAGGING
            && state == ViewPager.SCROLL_STATE_SETTLING)
        userScrollChange = true;

    else if (previousState == ViewPager.SCROLL_STATE_SETTLING
            && state == ViewPager.SCROLL_STATE_IDLE)
        userScrollChange = false;

    previousState = state;
}

Операторы if и else if не должны быть настолько явными, но я сделал это для ясности.

Ответ 2

Вы правы в использовании ViewPager.OnPageChangeListener:

@Override
public void onPageSelected(int arg0) {
    // programmatically-initiated                           
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {

}

@Override
public void onPageScrollStateChanged(int arg0) {
    // user-initiated touch scroll      
}

В качестве альтернативы вы можете использовать логические флаги, чтобы различать programmatically-initiated smooth scroll and a user-initiated touch scroll. Например, если вы используете setCurrentItem(int item) для программного изменения страницы, попробуйте:

boolean progChange = false;

....
....
....

progChange = true;
setCurrentItem(somePageId);     // Set progChange = true every time

....
....
....

Внутри ViewPager.OnPageChangeListener:

@Override
public void onPageSelected(int arg0) {

}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
    if (progChange) {
        // programmatically-initiated
    } else {
        // user-initiated touch scroll
    }

    // Set progChange to false;
    progChange = false;                 
}

@Override
public void onPageScrollStateChanged(int arg0) {

}

Ответ 3

Я основывался на ответе как правильный и в комментариях ниже.

Сначала я анализирую, как ведет себя полный слушатель:

USER
onPageScrollStateChanged:        1             SCROLL_STATE_DRAGGING
onPageScrollStateChanged:        2             SCROLL_STATE_SETTLING
onPageSelected:              SELECTION     
onPageScrollStateChanged:        0             SCROLL_STATE_IDLE

PROGRAMATIC
onPageScrollStateChanged:        2             SCROLL_STATE_SETTLING
onPageSelected:              SELECTION
onPageScrollStateChanged:        0             SCROLL_STATE_IDLE  

Выводы:

  • Как вы можете видеть, в обоих случаях события заканчиваются, когда onPageScrollStateChanged перемещается в SCROLL_STATE_IDLE, , это означает, что idle - это конец цикла

  • Пользовательское событие SCROLL_STATE_DRAGGING, а затем SCROLL_STATE_SETTLING , которые являются 2 states отличными от 1 state для программного события SCROLL_STATE_SETTLING

  • onPageSelected происходит до конца цикла, но после того, как мы сможем определить, было ли изменение вызвано пользователем или программно, , так что бы то, что произошло раньше, сообщит нам в этом пункте, если это был пользователем или нет

Решение:

Поэтому я использую List<Integer> reset каждый раз, когда заканчивается цикл, и чтобы узнать, вызвал ли пользователь событие в методе onPageSelected, я проверяю размер List. Если размер равен 2, это означает, что пользователь просматривает пейджер.

abstract class PagerListenerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {

    private List<Integer> validator = new ArrayList<>();

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

    @Override
    public void onPageSelected(int position) {
        if (validator.size() == 2) {
            userScroll(position);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        validator.add(state);
        if (ViewPager.SCROLL_STATE_IDLE == state) {
            validator.clear();
        }

    }

    protected abstract void userScroll(int position);
}

Теперь этот класс удобно наследовать другим, который ему нужен.