Ссылка на список ViewPager sh не работает должным образом - PullRequest
0 голосов
/ 26 мая 2020

У меня есть пользовательские ViewPager и PagerAdapter, которые загружают элементы внутри instantiateItem. Он работает нормально, если я инициализирую его в первый раз с заданным списком элементов.

Но когда я вызываю refre sh в списке, я хочу заполнить адаптер новым (совершенно другим) списком после При вызове viewPager.adapter?.notifyDataSetChanged() PagerAdapter перестает работать должным образом, и эти элементы являются пустыми страницами без содержимого, и я могу пролистывать их в пользовательском интерфейсе.

PageScreen не Fragment. Это просто контейнер ViewGroup, который раздувает макет и устанавливает значения вне указанного элемента c. Он похож на ViewHolder + Binder в RecyclerView.

Также 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
    }
}

Также я попытался правильно обновить элементы sh (я ожидаю, что это делается внутри PagerAdapter и ViewPager, когда я вызываю notifyDataSetChanged()), удаляя их из ViewPager contentView и вызывая instantiateItem() для каждого элемента . Но результат тот же, что и выше. Теперь каждая страница была пустой. Функция ниже добавлена ​​к 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()
    }

ОБНОВЛЕНИЕ: Мне удалось «исправить» это, установив высоту ViewPager на фиксированное значение вместо WRAP_CONTENT, но это не решение. Мне нужен ViewPager с динамической c высотой, потому что некоторые из его дочерних элементов могут иметь разную высоту + установка чего-то в stati c не является хорошим подходом в Android. Некоторые телефоны с квадратными дисплеями тогда могли обрезать страницу.

Когда я заменил все элементы, эти «пустые» страницы были элементами с высотой 0 пикселей и шириной 0 пикселей по неизвестной причине.

Если я заменил высоту ViewPager на значение dp, он "заработал". Но когда я заменил эти представления, первый элемент всегда был пустым. но когда я прокручивал к третьему и обратно к первому, элемент был там по какой-то причине.

Также у меня нет проблемы с высотой. У меня есть функция внутри ViewPager, которая устанавливает высоту на основе самого высокого ребенка в списке. Он работает, если список имеет значение c, но теперь он не работает, поскольку я обновляю sh это.

1 Ответ

0 голосов
/ 05 июня 2020

Воссоздание целого ViewPagerAdapter - решение этой проблемы.

Я вызвал API внутри onPageSelected() и запомнил позицию, возвращенную функции слушателя.

Затем я воссоздал весь адаптер следующим образом:

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

и после refre sh я прокрутил до запомненной позиции следующим образом:

setCurrentItem(position, true)

Это решение не будет оставил пустые страницы, но мне пришлось установить высоту c для моего ViewPager, что может быть проблемой на экранах mdpi, которые иногда не могут правильно перерисовать конкретное значение dp из макета XML. Телефон с этой проблемой, например, Sony Xperia E5 с экраном xhdpi, а часть моего ViewPager обрезана снизу.

Это нужно настраивать вручную с отдельным dimens.xml для обоих mdpi и xhdpi.

...