问题描述
这里的 ViewPager 遇到了一个非常奇怪的问题.我们在每个 ViewPager 页面上嵌入列表,并在更新列表数据时在列表适配器和视图页面适配器上触发 notifyDataSetChanged.
We're suffering from a very strange issue with ViewPager here. We embed lists on each ViewPager page, and trigger notifyDataSetChanged both on the list adapter and the view pager adapter when updating list data.
我们观察到,有时页面不会更新其视图树,即保持空白,有时甚至在分页时消失.当来回翻页几次时,内容会突然重新出现.似乎 Android 在这里缺少视图更新.我还注意到,在使用层次结构查看器进行调试时,选择一个视图总是会使其重新出现,显然是因为层次结构查看器会强制所选视图重新绘制自身.
What we observe is that sometimes, the page does not update its view tree, i.e. remains blank, or sometimes even disappears when paging to it. When paging back and forth a few times, the content will suddenly reappear. It seems as if Android is missing a view update here. I also noticed that when debugging with hierarchy viewer, selecting a view will always make it reappear, apparently because hierarchy viewer forces the selected view to redraw itself.
我无法以编程方式完成这项工作;使列表视图无效,甚至整个视图寻呼机无效.
I could not make this work programmatically though; invalidating the list view, or the entire view pager even, had no effect.
这与兼容性-v4_r7 库有关.我也尝试使用最新版本,因为它声称修复了许多与查看寻呼机相关的问题,但它使事情变得更糟(例如,手势被破坏,因此有时它不会让我再翻阅所有页面.)
This is with the compatibility-v4_r7 library. I also tried to use the latest revision, since it claims to fix many issues related to view pager, but it made matters even worse (for instance, gestures were broken so that it wouldn't let me page through all pages anymore sometimes.)
是否还有其他人也遇到过这些问题,或者您知道是什么原因造成的吗?
Is anyone else running into these issues, too, or do you have an idea of what could be causing this?
推荐答案
我们终于找到了解决方案.显然我们的实现遇到了两个问题:
We finally managed to find a solution. Apparently our implementation suffered of two issues:
- 我们的适配器没有删除
destroyItem()
中的视图. - 我们正在缓存视图,因此我们只需要膨胀一次布局,而且,由于我们没有在
destroyItem()
中删除视图,因此我们没有在中添加它instantiateItem()
但只是返回当前位置对应的缓存视图.
- our adapter did not remove the view in
destroyItem()
. - we were caching views so that we'd have to inflate our layout just once, and, since we were not removing the view in
destroyItem()
, we were not adding it ininstantiateItem()
but just returning the cached view corresponding to the current position.
我没有对 ViewPager
的源代码进行过深入研究 - 而且你必须这样做并不完全明确 - 但文档说:
I haven't looked too deeply in the source code of the ViewPager
- and it's not exactly explicit that you have to do that - but the docs says :
destroyItem()
删除给定位置的页面.适配器负责从其容器中删除视图,尽管它只必须确保在从 finishUpdate(ViewGroup) 返回时完成此操作.
destroyItem()
Remove a page for the given position. The adapter is responsible for removing the view from its container, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup).
和:
一个非常简单的 PagerAdapter 可以选择使用页面 View 本身作为关键对象,在创建后从 instantiateItem(ViewGroup, int) 中返回它们并将它们添加到父 ViewGroup 中.匹配的 destroyItem(ViewGroup, int, Object) 实现将从父 ViewGroup 中删除 View,并且 isViewFromObject(View, Object) 可以实现为 return view == object;.
A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int) after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object) implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object) could be implemented as return view == object;.
所以我的结论是 ViewPager
依赖其底层适配器在 instantiateItem()
/destroyItem()
中显式添加/删除其子项.也就是说,如果你的适配器是 PagerAdapter
的子类,那么你的子类必须实现这个逻辑.
So my conclusion is that ViewPager
relies on its underlying adapter to explicitly add/remove its children in instantiateItem()
/destroyItem()
. That is, if your adapter is a subclass of PagerAdapter
, your subclass must implement this logic.
旁注:如果您使用列表,请注意 this在 ViewPager
中.
Side note: be aware of this if you use lists inside ViewPager
.
这篇关于ViewPager 不重绘内容,保持/变为空白的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!