ViewPager2 мигает / перезагружается при пролистывании

#java #android #android-viewpager2

#java #Android #android-viewpager2

Вопрос:

Я пытаюсь создать приложение для Android, используя новый ViewPager2. Я добавил две страницы просмотра, разделенные видом, и когда вы проводите пальцем, обе страницы просмотра должны перемещаться. Оба пейджера просмотра перемещаются правильно, но по завершении жеста мигает просмотренный вид, а не просмотренный вид перезагружается, как показано в прикрепленном gif. Вот мой код для Activity, ViewPagerAdapter и Fragment. Любая помощь приветствуется

введите описание изображения здесь

     public class MainActivity extends FragmentActivity {

    ActivityMainBinding viewBinding;

    MyPager adapter1, adapter2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        List<String> data = populateData();

        adapter1 = new MyPager(this, data);
        adapter2 = new MyPager(this, data);

        viewBinding.viewPager.setAdapter(adapter1);
        viewBinding.viewPager2.setAdapter(adapter2);

        viewBinding.viewPager2.setOffscreenPageLimit(data.size());
        viewBinding.viewPager.setOffscreenPageLimit(data.size());

        viewBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            @Override
            public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                viewBinding.viewPager2.scrollTo(positionOffsetPixels, 0);
            }

            @Override
            public void onPageScrollStateChanged(final int state) {
                viewBinding.viewPager2.setCurrentItem(viewBinding.viewPager.getCurrentItem(), true);
            }
        });
        viewBinding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

            @Override
            public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
            }

            @Override
            public void onPageScrollStateChanged(final int state) {
                viewBinding.viewPager.setCurrentItem(viewBinding.viewPager2.getCurrentItem(), true);
            }
        });

    }
    private List<String> populateData() {
        List<String> data = new ArrayList<>();
        for (int x = 0; x < 10; x  ) {
            String derril = "derril "   x;
            data.add(derril);
        }
        return data;
    }
}
  
 public class MyPager extends FragmentStateAdapter {

    List<String> data;

    public MyPager(@NonNull FragmentActivity fragmentActivity, List<String> data) {
        super(fragmentActivity);
        this.data = data;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return DerrilFragment.newInstance(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}
  
 public class DerrilFragment extends Fragment {

    PizzaBinding viewBinding;

    String data;

    private DerrilFragment(String data) {
        this.data = data;
    }

    public static DerrilFragment newInstance(String data) {
        return new DerrilFragment(data);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        viewBinding = DataBindingUtil.inflate(inflater, R.layout.pizza, container, false);

        viewBinding.text.setText(data);

        return viewBinding.getRoot();

    }
}
  

Комментарии:

1. Почему у вас есть 2 ViewPagers? Вам нужен только 1.

2. потому что страницы просмотра разделены представлением. если вы можете сделать это в одном viewpager, мне было бы интересно услышать, как

3. Похоже, что ваши ViewPagers находятся друг над другом. Так что для меня это не имеет смысла.

4. Что насчет этого не имеет смысла? Один ViewPager сверху, разделенный view, затем второй ViewPager.

Ответ №1:

Вы можете реализовать с помощью RecyclerView .

 class MainActivity : AppCompatActivity() {
    private var isFirstFocused = false

    private val helper: SnapHelper = LinearSnapHelper()
    private val helper2: SnapHelper = LinearSnapHelper()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recycler1.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (isFirstFocused) recycler2.scrollBy(dx, dy)
            }
        })
        recycler2.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (!isFirstFocused) recycler1.scrollBy(dx, dy)
            }
        })
        recycler2.setOnTouchListener { v, event ->
            if (event.action  != null amp;amp; event.action == MotionEvent.ACTION_DOWN ) {
                isFirstFocused = false
                return@setOnTouchListener  true
            }
            return@setOnTouchListener false
        }
        recycler1.setOnTouchListener { v, event ->
            if (event.action  != null amp;amp; event.action == MotionEvent.ACTION_DOWN ) {
                isFirstFocused = true
                return@setOnTouchListener  true
            }
            return@setOnTouchListener false
        }
        helper.attachToRecyclerView(recycler1)
        helper2.attachToRecyclerView(recycler2)
        val manager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
        val manager2 = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false)
        recycler1.layoutManager = manager
        recycler2.layoutManager = manager2
        recycler2.adapter = Adapter(items)
        recycler1.adapter = Adapter(items)
    }

    private val items = listOf("One", "Two", "Three")

}

class Adapter(val list: List<String>) : RecyclerView.Adapter<Adapter.Holder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val view = LayoutInflater.from(parent.context).inflate(
            R.layout.activity_listview,
            parent,
            false
        )
        return Holder(view)
    }

    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.itemView.text_view.text = list[position]
    }

    override fun getItemCount() = list.size

    class Holder(view: View) : RecyclerView.ViewHolder(view)
}
  

Ответ №2:

Вы можете попробовать использовать adapter.setOffscreenPageLimit = n . Он устанавливает количество страниц, которые должны быть сохранены по обе стороны от текущей видимой страницы (страниц). Страницы, превышающие это ограничение, будут воссозданы из адаптера при необходимости, если у вас ограниченное количество страниц. Более подробная информация здесь.

Ответ №3:

В ваших setCurrentItem() обычаях (в разделе onPageScrollStateChanged() ) установите для второго параметра значение false

Это отключит анимацию (не навсегда) в ViewPager при программной настройке страницы, поэтому вы видите анимацию, похожую на flash.


Чтобы знать, почему:

Рассмотрим два ViewPagers A и B

Вы прокручиваете страницу с одной страницы на другую в A, что вызывает ту же прокрутку в ViewPager B. Как только вы полностью прокручиваете страницу с одной страницы на другую в A, значение currentItem внутренне устанавливается A, но не для B.

Теперь вы сообщаете B об изменении страницы путем вызова setCurrentItem([index], true) , который, независимо от вашей прокрутки, будет анимировать изменение страницы, вводящее flash (ваша индуцированная прокрутка сбрасывается в обычное состояние, и запускается анимация страницы для перехода с одной страницы на другую)

Ответ №4:

это выглядит немного подозрительно, что вы вызываете setCurrentItem inside onPageScrollStateChanged для каждого пройденного state … попробуйте добавить некоторые if и setCurrentItem только тогда, когда state==ViewPager2.SCROLL_STATE_IDLE

список состояний:

  • ViewPager2.SCROLL_STATE_IDLE
  • ViewPager2.SCROLL_STATE_DRAGGING
  • ViewPager2.SCROLL_STATE_SETTLING

ViewPager2.SCROLL_STATE_DRAGGING состояние обрабатывается в onPageScrolled методе (совместное смещение позиции, иначе. перетаскивание пальцем)

ViewPager2.SCROLL_STATE_SETTLING является ли автоматическая прокрутка (привязка) ViewPager2 к ближайшей странице — здесь я не уверен, что ViewPager2 перетаскивание «по коду» (совместное использование позиции с scrollTo ) также будет входить в это state , вызывая такое же поведение привязки (так же onPageScrolled ?).)… стоит протестировать, добавить туда несколько журналов

также: вы перетаскиваете один ViewPager2 и onPageScrolled вызываете scrollTo второй ViewPager2 . это может привести к вызову onPageScrolled call для этого второго прослушивателя, который вызывает первый ViewPager2 scrollTo метод и так далее… зацикливается. рассмотрите возможность динамической отмены регистрации слушателя, когда пользователь начнет перетаскивать ViewPager2 его, и повторной регистрации при завершении движения ( SCROLL_STATE_IDLE state )

Ответ №5:

Я думаю, проблема в том, что в методе onPageScrolled для обоих ViewPagers вы прокручиваете другой пейджер. Таким образом, обе страницы могут прокручивать друг друга одновременно. Например, если вы прокручиваете ViewPager_1, то его метод onPageScrolled будет прокручивать ViewPager_2, а поскольку ViewPager_2 теперь прокручивается, будет вызван его метод onPageScrolled, который будет прокручивать ViewPager_1 и наоборот. Итак, вам может потребоваться рассмотреть возможность применения проверки, что если touch удерживается в ViewPager_1, то код внутри метода onPageScrolled ViewPager_2 не должен выполняться. Или, если вы хотите избежать этих проверок. Затем registerOnPageChangeCallback / unregisterOnPageChangeCallback вызывает прослушиватель другого ViewPager при удержании касания.

             @Override
            public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
                viewBinding.viewPager.scrollTo(positionOffsetPixels, 0);
            }
  

Комментарии:

1. Проблема в том, что требование к этой функции заключается в том, что необходимо синхронизировать прокрутки между каждым viewpager