一旦不再可见,如何在 ViewPager2 中重置 ViewHolder 的视图状态?

How to reset the view state of a ViewHolder in ViewPager2, once it is not visible anymore?

我正在使用 ViewPager2ListAdapter 水平滚动浏览 Recycler.ViewHolder 项,一次显示一项。当内容不适合屏幕时,每个都可以垂直滚动。

一旦项目不再可见,我想重置它们的滚动状态,因为视图持有者可能会被另一个项目重用,而且它更整洁。

我知道如何在 ViewHolder 中重置滚动状态,但是我可以把这段代码放在哪里

我首先想到它可能在托管 ViewPager2 的片段中,我可以在其中注册回调 ViewPager2.OnPageChangeCallback 与 viewpager:

private var lastPosition = -1
private var callback = object: ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        if (lastPosition >= 0) {
            // reset scroll here
            val v: MyViewHolder = ???(position)
            v.resetScrollState()
        }
        lastPosition = position
    }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewpager = binding.itemPager
    viewpager.adapter = [...]
    viewpager.registerOnPageChangeCallback(callback)
}

(其中 binding.itemPager 指向 ViewPager2

但我不知道如何轻松获取视图持有者,除非将其存储(例如在一个集合中)以便我可以从 position 检索它。然后我仍然必须第一次正确设置 lastPosition 但它是次要的。

我的问题: 有什么办法

或者有更好的方法来处理这个问题吗?

我终于找到了。

对于给定的 lastPosition,可以通过以下方式获取视图持有者:

(viewpager.get(0) as RecyclerView).findViewHolderForAdapterPosition(lastPosition)
    as? MyViewHolder

所以回调变成:

private var callback = object: ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        if (lastPosition >= 0) {
            // reset scroll here
            val holder = (viewpager.get(0) as RecyclerView).findViewHolderForAdapterPosition(lastPosition) as? TodoEventAdapter.MyViewHolder
            if (holder != null)
                holder.resetScroll()
        }
        lastPosition = position
    }
}

我可以设置 lastPosition 的初始值并注册回调,例如在带有 ViewPager2.currentItem 的片段代码中:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewpager = binding.itemPager
    [...]
    lastPosition = viewpager.currentItem
    viewpager.registerOnPageChangeCallback(callback)
}

override fun onDestroyView() {
    [...]
    viewpager.unregisterOnPageChangeCallback(callback)
    super.onDestroyView()
}

其中binding.itemPager使用viewBinding,对应layout的ViewPager2实例

请注意,要显示的第一个位置可能来自参数,例如需要在起始位置显示特定项目的 activity。 lastPosition的初始值可以从这个参数中得到,也可以从已经设置的ViewPager2.currentItem值once/if中得到,如上图