我正在使用ViewPager2创建幻灯片。比如,这个幻灯片有三项内容,我希望在活动打开时显示第二项内容。我使用了setCurrentItem(int item, boolean smoothScroll)
方法,但它没有起作用,什么都没有发生。我该如何实现呢?
viewPager.adapter = adapter
viewPager.setCurrentItem(1, true)
我正在使用ViewPager2创建幻灯片。比如,这个幻灯片有三项内容,我希望在活动打开时显示第二项内容。我使用了setCurrentItem(int item, boolean smoothScroll)
方法,但它没有起作用,什么都没有发生。我该如何实现呢?
viewPager.adapter = adapter
viewPager.setCurrentItem(1, true)
我认为更容易、更可靠的解决方法是推迟到下一次运行周期,而不是使用不安全的延迟,例如:
viewPager.post {
viewPager.setCurrentItem(1, true)
}
final
。【不要问我为什么!】 - Bad LosersetCurrentItem(int item, boolean smoothScroll)
在ViewPager
中正常工作,但在ViewPager2
中并不如预期。最终,我通过将setCurrentItem(int item, boolean smoothScroll)
方法添加到延迟中来解决了这个问题,如下所示:
Handler().postDelayed({
view.viewPager.setCurrentItem(startPosition, false)
}, 100)
首先,我认为被接受的答案不应该是@hosseinAmini的,因为它建议使用延迟来解决问题。你应该首先寻找引起假定错误的原因,而不是信任像那样不合理的解决方案。
@Rune的提议是正确的,所以我在我的答案中引用他们的代码:
...
viewPager.post {
viewPager.setCurrentItem(1, true)
}
我唯一要争论的是上述观点认为他们的解决方案只是将该lambda推迟到下一个运行周期执行。这样做并不能使任何错误的工作正常运行。实际上,所做的是将该lambda的执行推迟到视图附加到窗口后,这意味着它也已经添加到了父视图中。确实,在附加到窗口之前更改当前 ViewPager2
项存在问题。以下是一些支持此说法的证据:
使用任何一个Handler
都不会像这样有效。
Handler(Looper.getMainLooper()).post {
viewPager.setCurrentItem(1, true) // Not working properly
}
从理论上讲,由于ViewPager2
已连接到窗口并获得了主Looper消息队列中的优先级,因此可能偶然起作用,但不应该依赖它,因为没有保证会起作用(甚至更有可能不起作用),即使它确实有效,进一步调查运行多个测试也应该能够说明我的观点。
View.handler
获取null
,这意味着该视图尚未附加到任何窗口。
View.handler // = null
尽管 Android UI 与主线程的主循环绑定在一起,这将始终唯一对应于主线程,因此也称为 UI 线程,但奇怪的设计选择在于处理程序在视图附加到窗口之前不与每个视图相关联。这可能是因为视图在未成为层次结构的一部分时无法在主线程上安排任何工作,这在实现调度视图更新的视图控制器时可能很有用(在这种情况下,它将使用 View 的处理程序(如果有)-或者如果没有,则跳过要调度的任务)。 viewPager.doOnAttach {
viewPager.setCurrentItem(1, true)
}
感谢您的建议!它更好地表达了实际意图,而不是依赖于 View.post
方法的行为。
不要使用定时器,因为可能会遇到很多概率状态,在这些状态中,用户可能拥有一个运行时间比100ms长得多的缓慢手机,此外,您也不希望定时器过慢,使其变得非常不可靠。
以下是我们所做的,我们设置一个听众到我们的ViewTreeObserver,并等待一组孩子已经在我们的ViewPager2的RecyclerView布局完成(它的内部工作)。 一旦我们确定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)
}
}
}
viewPager.setCurrentItem(1, false)
。 这里的“false”是关于平滑滚动的,当您的活动刚打开时,您无法平滑滚动您的viewPager2。 在onViewCreated()方法中的片段上进行了测试,它也不能与“true”一起工作,但可以与“false”一起工作。true
时,我的片段没有被调用 onResume
,这搞乱了事情。使用 false
就可以正常工作。显然是 ViewPager2
的一个 bug,但至少我们有一个可行的解决方案... - algrid setCurrentItem(position,smoothScroll)
方法来显示所选项目。为使其正常工作,您必须定义一个回调,这是一个示例: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)
方法,传递你的参数,然后从FragmentStateAdapter
类中调用createFragment(int position)
方法来显示你的fragment。我曾经尝试在 Handler().dely()
,viewPager2.post{}
以及 'viewPager2.get(0).post
中改变 viewpager2 页面,但都无法生效。 我使用的是带有 FragmentStateAdapter
和 Tablayout
的 ViewPager
。
最终解决方法是,在手动将 FragmentStateAdapter
绑定到 yourViewPager2View.adapter
后,改变 RecyclerView
在 ViewPager2
中的位置。
(yourViewPager2View[0] as RecyclerView).scrollToPosition(moveToTabNumber)
为什么
我的问题是在FragmentStateAdapter
中,onCreateFragment(position:Int):Fragmeet
函数总是以0位置开始显示fragment,无论我将页码设置为多少。
viewPager.setCurrentItem = pageNumber
我在FragmentStateAdapter
中检查了它的调用,它是在FragmentStateAdapter
中被调用的:
onBindViewHolder(final @NonNull FragmentViewHolder holder, int position)`
onBindViewHolder
调用 onCreateFragment(position:Int)
并传入我想要的页面编号。viewPager.setCurrentItem(pageNumber, false)
。在我的情况下,我在片段的onViewCreated
方法中调用了这些方法。希望这对您也能起作用。如果将第二个参数设置为“true”,则该方��调用将无效,原因未知。 - nadinnnnnnemViewPager.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
}
同时检查:
PagerAdapter中的getItem(int position)
否则,请粘贴您的代码。
我注意到,如果您选择不对视图进行动画处理,则在初始创建视图时它可以正常工作。
viewPager2.setCurrentItem(index, false)
根据您的用例,这通常是可以的 - 这个初始/默认项可能不需要动画。
和 @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);
}
});