#android #scroll #views #synchronized #android-viewpager
#Android #прокрутка #число просмотров #синхронизировано #android-viewpager
Вопрос:
У меня есть два ViewPagers — Pager1 и Pager2. Я добавил OnPageChangeListener в Pager1, и в обратном вызове onPageScrolled я вызываю Pager2.scrollTo(x, y), чтобы переместить его. Обе страницы просмотра прокручиваются плавно и синхронизируются, но проблема в том, что содержимое Pager2 не изменяется. Я проверил это с помощью LogCat — instantiateItem() для Pager2 вообще не вызывается.
В качестве обходного пути я добавил Pager2.setCurrentItem() в обратный вызов onPageSelected() для Pager1. Хотя при этом прокручиваются оба вида, они не синхронизируются с пикселем. Мне интересно, есть ли способ добиться этого эффекта без переопределения фактического класса ViewPager.
Ответ №1:
Решение, которое лучше всего работало для меня, состояло в том, чтобы проходить MotionEvent
OnTouchListener
между ViewPager
экземплярами. Пробовал поддельное перетаскивание, но оно всегда было медленным и глючным — мне нужен был плавный эффект, подобный параллаксу.
Итак, мое решение состояло в том, чтобы реализовать View.OnTouchListener
. Необходимо MotionEvent
масштабировать, чтобы компенсировать разницу в ширине.
public class SyncScrollOnTouchListener implements View.OnTouchListener {
private final View syncedView;
public SyncScrollOnTouchListener(@NonNull View syncedView) {
this.syncedView = syncedView;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
MotionEvent syncEvent = MotionEvent.obtain(motionEvent);
float width1 = view.getWidth();
float width2 = syncedView.getWidth();
//sync motion of two view pagers by simulating a touch event
//offset by its X position, and scaled by width ratio
syncEvent.setLocation(syncedView.getX() motionEvent.getX() * width2 / width1,
motionEvent.getY());
syncedView.onTouchEvent(syncEvent);
return false;
}
}
Затем установите его на свой ViewPager
sourcePager.setOnTouchListener(new SyncScrollOnTouchListener(targetPager));
Обратите внимание, что это решение будет работать только в том случае, если оба пейджера имеют одинаковую ориентацию. Если вам нужно, чтобы она работала для разных ориентаций — отрегулируйте syncEvent
координату Y вместо X.
Есть еще одна проблема, которую мы должны принять во внимание — минимальная скорость и расстояние броска, которые могут привести к смене страницы только одним пейджером.
Это можно легко исправить, добавив OnPageChangeListener
в наш пейджер
sourcePager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
//no-op
}
@Override
public void onPageSelected(int position) {
targetPager.setCurrentItem(position, true);
}
@Override
public void onPageScrollStateChanged(int state) {
//no-op
}
});
Ответ №2:
Вы пробовали beginFakeDrag()
?