RecyclerView LinearLayoutManager computeVerticalScrollOffset()未返回正确的值

时间:2015-05-20 22:23:10

标签: android android-recyclerview

我正在使用RecyclerView和相应的LinearLayoutManager。我在我的应用程序的一部分添加了一些自定义滚动功能,我将翻译自定义标题对象以及在此项目之后建模的RecyclerView的滚动:https://github.com/boxme/ParallaxHeaderViewPager(使用ListView而不是RecyclerView)。

我遇到了一个奇怪的问题。它会滚动一段时间,但它会跳几百像素。我添加了日志语句以查看LinearLayoutManager.computeVerticalScrollOffset()计算的偏移量,因为我确定滚动,偏移量从320到1200随机跳转,然后它将继续从该点开始适当地计算偏移量。

请参阅下面的答案我是如何解决这个问题的!

3 个答案:

答案 0 :(得分:8)

问题最终是我的列表中有一个非常大的隐形项目,然后是一堆较小的项目。事实证明,LinearLayoutManager.computeVerticalScrollOffset()在计算时会将平均行高考虑在内。这对我来说是一个问题,因为顶部的大项目抛弃了行的平均高度。我最后通过在顶部添加一些较小的隐形物品而不是一个较大的隐形物来解决这个问题,以保持平均行高精确。

我希望这有助于任何面临类似问题的人!

答案 1 :(得分:1)

感谢这个帖子终于找到了一种方法来准确地解决这个问题,在重写的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
    }

}

答案 2 :(得分:0)

对于任何想要它的人,这是java版本:

public class LinearLayoutManagerAccurateOffset extends LinearLayoutManager {

    private HashMap<Integer, Integer> mChildSizesMap;

    public LinearLayoutManagerAccurateOffset(Context context, int layoutType, boolean reverseLayout) {
        super(context, layoutType, reverseLayout);
        mChildSizesMap = new HashMap<>();
    }

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            mChildSizesMap.put(getPosition(child), child.getHeight());
        }

    }

    @Override
    public int computeVerticalScrollOffset(RecyclerView.State state) {

        if (getChildCount() == 0) {
            return 0;
        }

        View firstChild = getChildAt(0);
        int firstChildPosition = getPosition(firstChild);
        int scrolledY = -(int) firstChild.getY();
        for (int i = 0; i < firstChildPosition; i++) {
            scrolledY += mChildSizesMap.get(i);
        }
        return scrolledY;
    }
}