I have custom ViewPager and PagerAdapter which is loading items inside instantiateItem. It is working fine if I initialize it for the first time with set list of items.
But as I call refresh on the list and I want to populate Adapter with new (totally different) list, after calling viewPager.adapter?.notifyDataSetChanged(), PagerAdapter stops working properly and those items are blank pages without content and I can swipe through them in UI.
PageScreen is not Fragment. It is just ViewGroup container which is inflating layout and setting values out of specific item. It is similar to ViewHolder + Binder in RecyclerView.
Also instatiateItem() is called only once as i add new list and call notifyDataSetChanged(). At start it is called 3 items, which is amount of PageScreen items in first list.
//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()
Also tried this (same result):
//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() }
Adapter:
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
}
}
Also I tried to properly refresh items (I expect that this is done internally by PagerAdapter and ViewPager when I call notifyDataSetChanged()) by removing them from ViewPager contentView and calling instantiateItem() for each item. But same result as above. Now every single page was blank. Function below is added to 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()
}
UPDATE:
I managed to "fix" this by setting ViewPager height to fixed value instead WRAP_CONTENT but its not a solution. I want ViewPager with dynamic height, because some of its children can have different height + setting something to static is not good approach in Android. Some phones with square displays could have cropped page then.
What happened is as I replaced all items, those "blank" pages were items with 0px height and 0px width for some unknown reason.
If I replaced ViewPager height to dp value, it "worked". But as I replaced those Views, first item was always blank. but as I scrolled to third one and back to first, item was there for some reason.
Also I don't get that height problem. I have function inside ViewPager which is setting its height based on tallest child in list. It works if list is static, but it is not working now as I refresh that.
Recreating whole
ViewPagerAdapteris a solution for this problem.I called API inside
onPageSelected()and remembered position returned to listener function.Then I recreated whole adapter like this:
and after refresh I scrolled to remembered position like this:
This solution will not left blank pages, but I had to set static height for my
ViewPager, which can be a problem onmdpiscreens which sometimes cannot redraw particulardpvalue fromXMLlayout correctly. Phone with this problem is for exampleSony Xperia E5which hasxhdpiscreen and part of myViewPageris cropped from the bottom.This have to be tuned manually with separate
dimens.xmlfor bothmdpiandxhdpi.