Дифференциация между прокруткой и изменением страницы программы в ViewPager
У меня есть android.support.v4.view.ViewPager
в моем приложении, и я хотел бы провести различие между программно-инициированным гладким прокруткой и инициированным пользователем сенсорным прокруткой.
Я посмотрел на ViewPager.OnPageChangeListener
, и я считаю, что ответ может лежать там, но я просто не уверен, как это сделать.
Ответы
Ответ 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);
}
Теперь этот класс удобно наследовать другим, который ему нужен.