ViewPager2 默认位置

ViewPager2 default position

我正在使用 ViewPager2 创建幻灯片。例如,幻灯片有 3 个项目,我想在 activity 打开时显示第二个项目。我使用 setCurrentItem(int item, boolean smoothScroll) 方法,但它不起作用并且没有任何反应。我怎样才能实现它?

viewPager.adapter = adapter
viewPager.setCurrentItem(1, true)

mViewPager.setCurrentItem(1, true); ---> this is sufficient as you written above

应该可以, 如有疑问,请检查您的位置:

        @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) in PagerAdapter

或者粘贴您的代码。

setCurrentItem(int item, boolean smoothScroll)ViewPager 中可以正常工作,但在 ViewPager2 中不能按预期工作。最后,我通过将 setCurrentItem(int item, boolean smoothScroll) 方法添加到这样的延迟中来解决这个问题:

Handler().postDelayed({
     view.viewPager.setCurrentItem(startPosition, false)
}, 100)

首先,您需要在您想要的任何侦听器或按钮下初始化 Main activity 之后,您需要将此行.. 这里 MainActvity 是 Viewpager Main Class 你正在使用并且 2 是你想要移动的位置

 MainActivity main = (MainActivity ) mContext;
    main.selectTab(2, true);

不要使用计时器,你会 运行 进入很多可能的状态,在这些状态下,用户的速度很慢 phone 并且实际上需要比 100 毫秒更长的时间才能 运行,另外,你也不希望计时器太慢,让它变得荒谬 un-reliable。

下面我们执行以下操作,我们为我们的 ViewTreeObserver 设置一个侦听器并等待,直到在我们的 ViewPager2 的 RecyclerView 中布置了一组 children(它在内部工作)。一旦我们确定已经布置了 x 个项目,我们就开始 no-animation 滚动以从该位置开始。

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)
      }
   }
}

如上所述,您必须在 ViewPager2 上使用 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 class 将被调用以显示您的 片段

我认为更简单更可靠的解决方法是推迟到下一个 运行 周期而不是不安全的延迟,例如

viewPager.post {
  viewPager.setCurrentItem(1, true)
}

我尝试在 Handler().dely()viewPager2.post{} 中更改 viewpager2 页面,甚至 'viewPager2.get(0).post 也对我不起作用,我正在使用 ViewPagerFragmentStateAdapterTablayout

对我有用的是手动更改 ViewPager2 RecylerView 的位置 FragmentStateAdapteryourViewPager2View.adapter :

 (yourViewPager2View[0] as RecyclerView).scrollToPosition(moveToTabNumber)

为什么

我的问题是 FragmentStateAdapter 中的 onCreateFragment(position:Int):Fragmeet 函数总是在 0 位置 开始片段,无论我设置的页码是多少

viewPager.setCurrentItem = pageNumber

我检查了它在 FragmentStateAdapter 中的调用位置 它在 FragmentStateAdapter 中调用:

onBindViewHolder(final @NonNull FragmentViewHolder holder, int position)`

所以我只需要强制 onBindViewHolder 使用我想要的页码调用 onCreateFragment(position:Int)

首先,我认为接受的答案不应该是@hosseinAmini 的,因为它建议使用延迟来解决该问题。您应该首先寻找假定的错误是由什么引起的,而不是相信那样不合理的解决方案。

@Rune 的提议是正确的,相反;所以我在回答中引用了他们的代码:

viewPager.post {
    viewPager.setCurrentItem(1, true)
}

我唯一要争论的是前面提到的人认为他们的解决方案只是在下一个 运行 周期中推迟执行该 lambda。这不会使任何有问题的东西正常工作。相反,它实际上正在做的是将该 lambda 的执行推迟到视图已附加到 window,这意味着它也已添加到父视图。事实上,在附加到 window 之前更改当前 ViewPager2 项目似乎存在问题。支持这一说法的一些证据如下:

  • 使用任何一个 Handler 都不会那么有效。

    Handler(Looper.getMainLooper()).post {
        viewPager.setCurrentItem(1, true) // Not working properly
    }
    

    从理论上讲,由于 ViewPager2 附加到 window 在主循环程序的消息队列中获取优先级,它可能会偶然起作用,但这永远不应该依赖因为不能保证它会起作用(它更有可能不会起作用),如果它甚至被证明起作用,进一步的调查运行宁多测试应该使我的观点清楚。

  • View.handler 得到 null,这意味着视图还没有附加到任何 window。

    View.handler // = null
    

    尽管 Android UI 被绑定到主循环程序,它将始终唯一对应于主线程——因此也称为 UI 线程——一个奇怪的设计选择仍然存在在处理程序中没有关联到每个视图,直到它们附加到 window。这可能是因为视图不属于层次结构的一部分时无法在主线程上安排任何工作,这可能在实现一个视图控制器时很有用,该视图控制器在不知道其生命周期的情况下安排视图更新(在在这种情况下,它将使用 View 的处理程序(如果有的话)——或者如果 none).

    则跳过它要进行的任何调度

编辑:

此外,@josias 在评论中指出使用它会更清楚:

viewPager.doOnAttach {
    viewPager.setCurrentItem(1, true)
}

感谢您的建议!它更好地表达了实际意图,而不是依赖于 View.post 方法的行为。

我遇到了同样的问题。在我的例子中,我默认设置 viewPager2 Gone,直到网络请求成功,我通过在使 viewPager2 可见后设置 CurrentItem 来修复它。

不要在 'post' 中使用计时器和所有其他东西,这不是可靠的解决方案,只是一段有味道的代码。

改为尝试使用 viewPager.setCurrentItem(1, false)。 'false' 是关于 smoothScroll 的,当你的 activity 刚打开时,你无法平滑滚动你的 viewPager2。在 onViewCreated() 方法的一个片段上测试它,它也不适用于“true”,但适用于“false”

我的回答现在可能没有帮助,但我认为 post 我的经验没有坏处,我刚刚使用 ViewPager 和 ViewPager2 遇到了这个问题,意外地通过更改一些行代码顺序解决了它。

这是 ViewPager 的 (java) 解决方案:

    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 开始新活动,则无需在 onResume 功能中使用 wordViewPager.setCurrentItem(item, smoothScroll) 返回到开始新活动前最后选择的选项卡 activity 您只需在 onStop 函数中保存 ViewPager/ViewPager2 位置,如 vpPisition = wordViewPager.getCurrentItem();

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.setCurrentItem(index, false)

根据您的用例,这通常没问题 - 这个 initial/default 项目可能不需要动画。