ViewPager 列表刷新无法正常工作

ViewPager list refresh is not working properly

我有自定义 ViewPagerPagerAdapter,它们正在 instantiateItem 中加载项目。如果我第一次使用设置的项目列表初始化它,它工作正常。

但是当我在列表上调用刷新并且我想用新的(完全不同的)列表填充适配器时,在调用 viewPager.adapter?.notifyDataSetChanged() 之后,PagerAdapter 停止正常工作并且那些项目是没有内容的空白页面,我可以在 UI.

中滑动它们

PageScreen 不是 Fragment。它只是 ViewGroup 容器,它正在膨胀布局并设置特定项目的值。类似于RecyclerView中的ViewHolder + Binder.

另外 instatiateItem() 在我添加新列表并调用 notifyDataSetChanged() 时只调用一次。一开始它被称为 3 项,这是第一个列表中 PageScreen 项的数量。

//init
val pages = mutableListOf<PageScreen>()
pages.add(PageScreen(activity, app, itemJs1, onClick = {onItemClicked(itemJs1.id)}))
pages.add(PageScreen(activity, app, itemJs2, onClick = {onItemClicked(itemJs2.id)}))
pages.add(PageScreen(activity, app, itemJs3, onClick = {onItemClicked(itemJs3.id)}))

swipePager.adapter = CustomPagerAdapter(pages).also { it.notifyDataSetChanged() }

...

//on refresh after API call
pages.clear()

contentList.forEach{item-> pages.add(PageScreen(activity, app, item, onClick = {onItemClicked(item.id)}))}

(swipePager.adapter as? CustomPagerAdapter)?.notifyDataSetChanged()

也试过这个(同样的结果):

//on refresh after API call

val newPages = mutableListOf<PageScreen>()

contentList.forEach{item-> newPages.add(PageScreen(activity, app, item, onClick = {onItemClicked(item.id)}))}

swipePager.adapter = CustomPagerAdapter(newPages).also { it.notifyDataSetChanged() }

适配器:

class CustomPagerAdapter(private var pageList: MutableList<PageScreen>) : PagerAdapter() {
    override fun isViewFromObject(view: View, `object`: Any): Boolean {
        return view == `object`
    }

    override fun getCount(): Int {
        return pageList.size
    }

    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
        container.removeView(`object` as View)
    }

    override fun instantiateItem(container: ViewGroup, position: Int): View {
        val layout = pageList[position].getScreen(container)
        container.addView(layout)
        return layout
    }
}

我还尝试通过将项目从 ViewPager contentView 中移除并为每个项目调用 instantiateItem() 来正确刷新项目(我希望这是在我调用 notifyDataSetChanged() 时由 PagerAdapter 和 ViewPager 在内部完成的)。但是结果和上面一样。现在每一页都是空白的。 CustomPagerAdapter.

添加了以下函数
fun refreshItems(vp: ViewPager, data: MutableList<PageScreen>){
        pageList.apply {
            forEachIndexed{pos, item->
                item.screenView?.let { sv->
                    destroyItem(vp, pos, sv)
                }
            }
            clear()
            addAll(data)
            forEachIndexed { pos, _ -> instantiateItem(vp, pos) }
        }
        notifyDataSetChanged()
    }

更新: 我设法 "fix" 通过将 ViewPager 高度设置为固定值而不是 WRAP_CONTENT 但这不是解决方案。我想要具有动态高度的 ViewPager,因为它的一些 children 可以有不同的高度 + 在 Android 中将某些东西设置为静态不是好的方法。一些带有方形显示屏的手机可能会裁剪页面。

发生的事情是当我替换所有项目时,那些 "blank" 页面是高度为 0px 和宽度为 0px 的项目,原因不明。

如果我将 ViewPager 高度替换为 dp 值,它 "worked"。但是当我替换那些视图时,第一项始终是空白的。但是当我滚动到第三个并返回到第一个时,出于某种原因,项目在那里。

我也不知道身高问题。我在 ViewPager 中有一个函数,它根据列表中最高的 child 来设置它的高度。如果列表是静态的,它可以工作,但是当我刷新它时它现在不工作了。

重新创建整个 ViewPagerAdapter 是解决此问题的方法。

我在 onPageSelected() 中调用了 API 并记住了返回到侦听器函数的位置。

然后我像这样重新创建了整个适配器:

swipePager.apply {
   adapter = null
   adapter = CustomPagerAdapter(newPages)
   adapter?.notifyDataSetChanged()
   invalidate()
}

刷新后我滚动到这样记住的位置:

setCurrentItem(position, true)

此解决方案不会留下空白页,但我必须为我的 ViewPager 设置静态高度,这在 mdpi 屏幕上可能是个问题,有时无法重绘特定 dp XML 布局中的值正确。 Phone 例如 Sony Xperia E5 有这个问题,它有 xhdpi 屏幕,我的 ViewPager 的一部分从底部被裁剪。

对于 mdpixhdpi,必须使用单独的 dimens.xml 手动调整。