Android viewpager синхронизировал прокрутку

#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() ?