关于在ViewPager2中获取当前选中Item的View控件

前言

       和同事一起开发了一个自己的树洞App,由于功能需要,需要实现类似于知乎的上一条、下一条滑动的效果,首先想到的就是ViewPager,来实现垂直滑动,但是ViewPager默认是左右滑动的,如果用的话,需要对ViewPager进行重写(网上有很多方案,这里就不做说明了),来进行上下滑动,所以就想到了其他方法。比如RecyclerView也能够来实现,不过也需要对PagerSnapHelper进行操作。因为item里面需要用到刷新控件来实现上一条、下一条的效果,所以也就放弃了RecyclerView。最终,选中了ViewPager2来实现这个功能

ViewPager2说明

       viewPager2是谷歌新出的控件,相当于ViewPager+RecyclerVIew的结合,内部是对RecyclerVIew的封装,也可以直接使用RecyclerView.Adapter来进行数据适配,帮我们实现了一些ViewPager的效果,所以很符合我们的需求,方便快捷。

问题

       由于Item中有ScrollerView控件,需要实现上下滑动超过一屏的情况,所以从第一条Item滑动到第二条Item之后,再滑回来,由于复用的问题,导致第一条Item的数据显示在最低端,影响用户的体验,希望能够在每次切换的时候,用户看到的UI永远都是当前Item的最顶端。这样的话,直接在Adapter中对ScrollView进行操作肯定是没有效果的,只有被销毁的Item再次创建才会符合我们的要求。

解决思路

       根据上面的问题,想到了解决的思路:那就是获取当前选中的Item,然后拿到item中的View,比如ScrollerView,对其进行scrollTo(0,0)就能够满足我们的需求了嘛。按照这个思路,进行了调试,发现由于RecyclerView的Adapter复用的机制,导致没办法直接拿到Item中的View,在网上找了多种解决方案都不行,没办法实时拿到当前选中的Item。最后,想到了曲线救国,既然ViewPager2是对RecyclerVIew进行的封装,那么能不能通过RecyclerVIew的一些方法进行解决了,就去查了一下关于RecyclerView的获取指定item的View的方案,发现还是有方法的。

解决方案

一开始用的是

(viewPager2.adapter as SquareAp).getViewByPosition(viewPager2.getChildAt(0),position,R.id.scrollerView)

因为getViewByPosition需要传RecyclerView的对象,所以才会有viewPager2.getChildAt(0)这个方法。
通过验证,发现不行,获取到的View控件有时会为null,应该还是和复用有关系。
没办法,只能修改方案了。
通过查找发现,RecyclerVIew可以通过layoutManager的findViewByPosition方法来获取到指定Item的View。大喜!这不就是我们想要的嘛?既然找到的方法,那就上手干吧!
先通过ViewPager2获取到内部的RecyclerVIew的对象

val recyclerView= viewPager2.getChildAt(0) as RecyclerView

在通过recyclerVIew调用layoutManager的findViewByPosition方法获取到指定position对象的View

val view = recyclerView.layoutManager?.findViewByPosition(position)

到了这一步,基本就解决了我们的问题。
最后,通过View找到scrollerView

val scrollView = view?.findViewById<NestedScrollView>(R.id.scroll_view)

这样,我们就可以对scrollerVIew进行操作了

scrollView.scrollTo(0, 0)

到此,我们的问题就完美结局了。
还有一点要说明一下,ViewPager2的滑动监听方法和VIewPager有很大区别。

最后

奉上关于ViewPager2中获取指定Item的View控件的完整代码

viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                if (position < selectPosition) {
                    //往上滑
                    GlobalScope.launch(Dispatchers.IO) {
                        delay(50)
                        val view = recyclerView.layoutManager?.findViewByPosition(position)
                        val scrollView = view?.findViewById<NestedScrollView>(R.id.scroll_view)
                        if (scrollView != null) {
                            withContext(Dispatchers.Main) {
                                scrollView.scrollTo(0, 0)
                            }
                        }
                    }
                }
                selectPosition = position
            }
        })

如果你有其他好的解决方案,欢迎留言或+好友讨论…

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值