ViewPager2 положение по умолчанию
Я создаю слайд-шоу с ViewPager2. Например, в слайд-шоу есть 3 элемента, и я хочу показать второй элемент при открытии действия. я использую setCurrentItem(int item, boolean smoothScroll)
метод, но он не работает, и ничего не происходит. Как мне этого добиться?
viewPager.adapter = adapter
viewPager.setCurrentItem(1, true)
13 ответов
setCurrentItem(int item, boolean smoothScroll)
правильно работает в ViewPager
но в ViewPgar2
это не работает, как ожидалось. Наконец, я столкнулся с этой проблемой, добавив setCurrentItem(int item, boolean smoothScroll
) метод задержки:
Handler().postDelayed({
view.viewPager.setCurrentItem(startPosition, false)
}, 100)
Я думаю, что более легкое и надежное решение - отложить следующий цикл выполнения вместо небезопасной задержки, например
viewPager.post {
viewPager.setCurrentItem(1, true)
}
Не используйте таймеры, вы столкнетесь с множеством вероятных состояний, в которых у пользователя медленный телефон, и на самом деле для запуска требуется намного больше, чем 100 мс, также вы не захотите слишком медленный таймер, что сделает его смехотворным ненадежный.
Ниже мы делаем следующее: устанавливаем слушателя для нашего ViewTreeObserver и ждем, пока определенное количество дочерних элементов не будет размещено в RecyclerView нашего ViewPager2 (это внутренняя работа). Как только мы уверены, что x количество элементов размещено, мы начинаем прокрутку без анимации, чтобы начать с позиции.
val recyclerView = (Your ViewPager2).getChildAt(0)
recyclerView.apply {
val itemCount = adapter?.itemCount ?: 0
if(itemCount >= #(Position you want to scroll to)) {
viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
// False for without animation scroll
(Your ViewPager2).scrollToPosition(#PositionToStartAt, false)
}
}
}
Во-первых, мне жаль, что принятый ответ (@hosseinAmini) - это тот, который предлагает использовать тупую задержку для решения проблемы. Сначала вам следует выяснить, чем вызвана предполагаемая ошибка, а не доверять необоснованным решениям, подобным этому.
Предложение @Rune правильное; поэтому я цитирую его код в своем ответе:
viewPager.post { viewPager.setCurrentItem(1, true) }
Единственное, о чем я буду спорить, - это уверенность вышеупомянутого человека в том, что его решение просто откладывает выполнение этой лямбды в следующем цикле выполнения. Это не заставит ничего работать правильно. На самом деле это делается вместо того, чтобы отложить выполнение этой лямбды до того, как представление было прикреплено к окну, что означает, что оно также было добавлено к родительскому. Действительно, похоже, есть проблема с изменением текущего
ViewPager2
элемент до того, как он был прикреплен к окну. Следуют два доказательства того, что я говорю:
Используя любой
Handler
не будет работать так же эффективно.Handler(Looper.getMainLooper()).post { viewPager.setCurrentItem(1, true) // Not working properly }
View.handler
получаетnull
, что означает, что представление еще не было прикреплено ни к какому окну.View.handler // = null
Попробуйте использовать
viewPager.setCurrentItem(1, false)
. Это «false» относится к smoothScroll, вы не можете плавно прокручивать viewPager2, когда ваша активность только что открыта. Протестировал на фрагменте в методе onViewCreated(), тоже не работает с «true», но работает с «false»
Как было сказано выше, вы должны использовать setCurrentItem(position, smoothScroll)
на ViewPager2, чтобы показать выбранный элемент. Чтобы это работало, вам нужно определить обратный вызов, вот пример:
ViewPager2.OnPageChangeCallback callback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
}
};
И затем вы должны зарегистрировать его следующим образом:
viewPager.registerOnPageChangeCallback(callback);
Также не забудьте отменить регистрацию:
viewPager.unregisterOnPageChangeCallback(callback);
Когда ты звонишь setCurrentItem(position)
метод, который он вызовет onPageSelected(int position)
метод из вашего обратного вызова, передающий ваш аргумент, а затем методcreateFragment(int position)
от FragmentStateAdapter
будет вызван класс, чтобы показать ваш фрагмент.
mViewPager.setCurrentItem(1, true); ---> этого достаточно как ты написал выше
Это должно работать, если сомневаетесь, просто проверьте свою позицию:
@Override
public void onPageSelected(int i) {
if (LOG_DEBUG) Log.v(TAG, " ++++++++ onPageSelected: " + i);
mViewPager.setCurrentItem(i);
//TODO You can use this position: to write other dependent logic
}
а также проверить
getItem(int position) в PagerAdapter
или вставьте свой код.
Я попытался изменить страницу viewpager2 в Handler().dely()
или viewPager2.post{}
или даже 'viewPager2.get(0).post
у меня тоже не сработало, использую ViewPager
с FragmentStateAdapter
с Tablayout
.
Что сработало для меня, так это изменение положения RecylerView
в ViewPager2
после привязки FragmentStateAdapter
к yourViewPager2View.adapter
вручную:
(yourViewPager2View[0] as RecyclerView).scrollToPosition(moveToTabNumber)
Почему
Моя проблема onCreateFragment(position:Int):Fragmeet
функционировать в FragmentStateAdapter
всегда начинать фрагмент с позиции 0 независимо от того, какой pageNumber я установил для страницы
viewPager.setCurrentItem = pageNumber
Я проверил, где он звонит FragmentStateAdapter
это называется в FragmentStateAdapter
:
onBindViewHolder(final @NonNull FragmentViewHolder holder, int position)`
так что все, что мне нужно, это заставить onBindViewHolder
звонить onCreateFragment(position:Int)
с номером страницы, который я хотел.
Я заметил, что он отлично работает, когда представление изначально создается, если вы решили не анимировать его.
viewPager2.setCurrentItem(index, false)
Обычно это нормально в зависимости от вашего варианта использования - этот начальный элемент / элемент по умолчанию, вероятно, не нужно анимировать.
Сначала вам нужно инициализировать основное действие под любым слушателем или кнопкой, которую вы хотите, затем. После этого вам нужно поместить эту строку... здесь MainActvity - это используемый вами основной класс Viewpager, а 2 - это позиция, куда вы хотите переместиться.
MainActivity main = (MainActivity ) mContext;
main.selectTab(2, true);
Мой ответ может быть бесполезен сейчас, но я не вижу вреда для публикации моего опыта, я просто пришел к этой проблеме с помощью ViewPager и ViewPager2 и неожиданно решил ее, просто изменив порядок некоторых строковых кодов.
Вот (java) решение для ViewPager:
reviewWordViewPager.addOnPageChangeListener(changeListener);
reviewWordViewPager.setCurrentItem(viewPosition, true/false);
reviewWordTabIndicator.setupWithViewPager(reviewWordViewPager, true);
(Java) решение для ViewPager2:
wordViewPager.registerOnPageChangeCallback(viewPager2OnPageChangeCallback);
wordViewPager.setCurrentItem(vpPosition, true/false);
new TabLayoutMediator(tabIndicator, wordViewPager,
((tab, position) -> tab.setText(viewPagerTitle[position]))).attach();
Я не искал ViewPager2, нужен ли ему следующий старый код, используемый в ViewPager
@Override
public int getItemPosition(@NonNull Object object) {
// refresh all fragments when data set changed
return POSITION_NONE;
}
Но на удивление нет необходимости в нем во ViewPager2 для решения возникшей у меня проблемы, надеюсь, это поможет другим.
Если вы используете
context.startActivity
чтобы начать новую деятельность не нужно использовать
wordViewPager.setCurrentItem(item, smoothScroll)
в вашей
onResume
функция, чтобы вернуться к последней выбранной вкладке перед началом нового действия, вы просто сохраняете позицию ViewPager / ViewPager2, например
vpPisition = wordViewPager.getCurrentItem();
в
onStop
функция.
vpPisition
это глобальная переменная.
как @Daniel Kim, но версия Java
RecyclerView rvOfViewPager2 = (RecyclerView) viewPager2.getChildAt(0);
rvOfViewPager2.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
rvOfViewPager2.getViewTreeObserver().removeOnGlobalLayoutListener(this);
viewPager2.setCurrentItem(currentTabId, false);
}
});
Я встретил ту же проблему. В моем случае я делаю viewPager2 Gone по умолчанию до тех пор, пока сетевые запросы не будут выполнены успешно, я исправляю это, устанавливая CurrentItem после того, как сделаю viewPager2 видимым.