ViewPager2 默认位置

Posted

技术标签:

【中文标题】ViewPager2 默认位置【英文标题】:ViewPager2 default position 【发布时间】:2019-10-12 04:35:04 【问题描述】:

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

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

【问题讨论】:

第二项是1,从0开始计数。 @shb 感谢您的回复,但我写错了示例代码。在我的代码中,这是 1,它不起作用 你可能想分享更多代码。您共享的代码完美运行。分享您的 viewPager 适配器类以及您调用它的位置。 【参考方案1】:

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

viewPager.post 
  viewPager.setCurrentItem(1, true)

【讨论】:

在浪费了几天时间寻找 my 代码中的错误之后,我独立地找到了这个解决方案。提示:如果所有其他方法都失败,请尝试将包含初始项目位置的字段设为final。 【别问我为什么! ] 你也可以用viewPager.doOnAttach ... 代替viewPager.post ... ,这样可能会更清楚是怎么回事,因为问题好像不是直接的与运行周期有关,但与未附加到窗口的 viewPager 有关。另见 Davide 的解释。【参考方案2】:

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

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

【讨论】:

这对我也有效。但对我来说,这不是一个解决方案,它是一个 hack(谁知道让它可靠工作的延迟时间)。破解有漏洞的 android 组件……希望 Google 能尽快修复它,这样我们就不需要再破解它了…… 我实际上花了很多时间试图弄清楚为什么当我调用它时我的标签没有被更改。太糟糕了,我们需要基本功能的解决方法 虽然我已经在我的帖子中解释了这个答案有什么问题,但我会在这里提到原因,以证明我的反对意见是正确的。真是简单明了,怎么能随便耽误事???这对最终用户是有害的,当他们的手机可能更快时,他们将不得不等待每秒 1/10 秒,或者可能有一个慢速手机,需要更多时间才能准备好,让错误出现。很遗憾你的答案被接受了【参考方案3】:

不要使用定时器,你会遇到很多可能的状态,用户的手机速度很慢,实际上运行时间超过 100 毫秒,而且你不希望定时器太慢让它变得非常不可靠。

下面我们执行以下操作,我们为 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)
      
   

【讨论】:

Ughhh,有问题的 Android 组件的解决方法多么疯狂:( 目前唯一合理的解决方案 这应该是公认的答案。【参考方案4】:

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

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

viewPager.post 
    viewPager.setCurrentItem(1, true)

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

使用任何Handler 都不会有效。

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

从理论上讲,它可能会由于 ViewPager2 附加到主循环器的消息队列中获取优先级的窗口而偶然起作用,但这不应该被依赖,因为不能保证它''ll 工作(它更可能不会),如果它甚至被证明是工作,运行多个测试的进一步调查应该清楚我的观点。

View.handler 得到null,这意味着该视图尚未附加到任何窗口。

View.handler // = null

尽管 Android UI 被绑定到主循环器,它总是唯一地对应于主线程 - 因此也称为 UI 线程 - 一个奇怪的设计选择在于处理程序不与每个视图相关联,直到它们被附加到一个窗口。这可能是因为视图无法在主线程上调度任何工作,而它们不是层次结构的一部分,这在实现一个调度视图更新但不知道其生命周期的视图控制器时可能会变得有用(在在这种情况下,它会使用View 的处理程序(如果有的话)——或者如果没有,就跳过调度程序)。

编辑:

另外,@josias 在评论中指出使用起来会更清晰:

viewPager.doOnAttach 
    viewPager.setCurrentItem(1, true)

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

【讨论】:

【参考方案5】:

如上所述,您必须在 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 类的方法 createFragment(int position) 以显示您的 片段

【讨论】:

不幸的是,这正是我所做的,但它不起作用(版本 2 可能仍然有问题)。实际上回调被正确调用,但是请求适配器创建第一个片段(大多数时候,有时它可以工作 - 因此,事件驱动的 Android 方法中可能存在竞争条件)。使用版本 1.0.0... 我会推荐你​​关注这篇文章raywenderlich.com/8192680-viewpager2-in-android-getting-started【参考方案6】:

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

        

还要检查

PagerAdapter 中的getItem(int position)

或者粘贴你的代码。

【讨论】:

【参考方案7】:

不要使用计时器和所有带有“post”的东西,这不是可靠的解决方案,只是一段有味道的代码。

请尝试使用viewPager.setCurrentItem(1, false)。那个'假'是关于smoothScroll的,当你的活动刚刚打开时,你不能平滑滚动你的viewPager2。在 onViewCreated() 方法中的片段上对其进行了测试,它也不适用于“true”,但适用于“false”

【讨论】:

在页面开头设置 false 时对我来说很好【参考方案8】:

我尝试更改Handler().dely()viewPager2.post 甚至'viewPager2.get(0).post 中的viewpager2 页面对我也不起作用,我将ViewPagerFragmentStateAdapterTablayout 一起使用。

对我有用的是手动更改 ViewPager2RecylerView 的位置 绑定后 FragmentStateAdapteryourViewPager2View.adapter

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

为什么

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

viewPager.setCurrentItem = pageNumber

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

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

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

【讨论】:

您可以在视图出现之前尝试使用viewPager.setCurrentItem(pageNumber, false)。就我而言,我在 Fragment 的 onViewCreated 方法中调用了这些。希望它对你有用,就像它对我一样。如果将第二个参数设置为true,方法调用将不起作用,不知道为什么.. 非常感谢!您的技巧帮助我解决了另一个 ViewPaer2 之谜: setCurrentItem(x,false) 在 x=0 时导致双重 onPageSelected() 调用;有趣的是,当 x!=0 时,一切都按预期工作。【参考方案9】:

首先,您需要在您想要的任何侦听器或按钮下初始化 Main 活动,然后您需要将这条线.. 这里 MainActvity 是你正在使用的 Viewpager Main Class 和 2 是你要移动的位置

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

【讨论】:

【参考方案10】:

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

【讨论】:

【参考方案11】:

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

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

    reviewWordViewPager.addOnPageChangeListener(changeListener);
    reviewWordViewPager.setCurrentItem(viewPosition, true/false);
    reviewWordTabIndicator.setupWithViewPager(reviewWordViewPager, true);

ViewPager2 的(Java) 解决方案:

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) 在开始新活动之前返回最后选择的选项卡,您只需保存 ViewPager/ViewPager2 位置,如 @987654327 @ 在onStop 函数中。

vpPisition 是一个全局变量。

【讨论】:

【参考方案12】:

作为@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);
        
    );

【讨论】:

【参考方案13】:

我注意到,如果您选择不为其设置动画,则在最初创建视图时它可以正常工作。

viewPager2.setCurrentItem(index, false)

这通常很好,具体取决于您的用例 - 这个初始/默认项目可能不需要动画。

【讨论】:

以上是关于ViewPager2 默认位置的主要内容,如果未能解决你的问题,请参考以下文章

ViewPager2 selectCurrentItem - 选择选项卡,但在此选项卡内放置错误的片段

LinearLayout 中的 AnimateLayoutChanges=true 在 ViewPager2 中不起作用

Android----------- Banner2 广告图片轮播ViewPager2实现

Android----------- Banner2 广告图片轮播ViewPager2实现

Android----------- Banner2 广告图片轮播ViewPager2实现

移除 ViewPager2 Overscroll 动画