RecyclerView LinearLayoutManager computeVerticalScrollOffset() не возвращает правильное значение

Я работаю с RecyclerView и соответствующим LinearLayoutManager. Я добавлял некоторые настраиваемые функции прокрутки в часть моего приложения, где я бы перевел пользовательский объект заголовка вместе со списком RecyclerView, смоделированным после этого проекта: https://github.com/boxme/ParallaxHeaderViewPager ( который использует ListView вместо RecyclerView).

Я столкнулся с странной проблемой. На некоторое время она прокручивается, но потом она скачет несколько сотен пикселей. Я добавил операторы журналов, чтобы увидеть смещение, вычисленное LinearLayoutManager.computeVerticalScrollOffset(), когда я прокрутил его достаточно уверенно, смещение было случайным образом перескакивает с 320 до 1200, после чего оно будет продолжать вычислять смещение соответственно с этой точки.

См. мой ответ ниже о том, как я это решил!

Ответ 1

Проблема заключалась в том, что у меня был очень большой невидимый элемент в моем списке, за которым последовала куча мелких предметов. Оказывается, LinearLayoutManager.computeVerticalScrollOffset() учитывает среднюю высоту строки при расчете. Это вызвало у меня проблему, так как этот большой элемент наверху отбрасывал среднюю высоту строк. Я решил это решить, добавив несколько меньших невидимых предметов сверху, а не один большой, чтобы сохранить среднюю высоту строки.

Я надеюсь, что это поможет любому, кто сталкивается с подобной проблемой!

Ответ 2

Благодаря этой теме, наконец, нашли способ решить эту проблему, разместив ниже код для переопределенного LinearLayoutManager, извините за его kotlin :(, вы также можете прочитать об этом в более подробно здесь

class LinearLayoutManagerWithAccurateOffset(context: Context?) : LinearLayoutManager(context) {

    // map of child adapter position to its height.
    private val childSizesMap = mutableMapOf<Int, Int>()

    override fun onLayoutCompleted(state: RecyclerView.State?) {
        super.onLayoutCompleted(state)
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            childSizesMap[getPosition(child)] = child.height
        }
    }

    override fun computeVerticalScrollOffset(state: RecyclerView.State?): Int {
        if (childCount == 0) {
            return 0
        }
        val firstChildPosition = findFirstVisibleItemPosition()
        val firstChild = findViewByPosition(firstChildPosition)
        var scrolledY: Int = -firstChild.y.toInt()
        for (i in 0 until firstChildPosition) {
            scrolledY += childSizesMap[i] ?: 0
        }
        return scrolledY
    }

}