Android获取RecyclerView滑动距离方法详细讲解

先说能用的究极解决方案,大家着急的直接复制走,以后想了解再过来看

没有header,且所有Item的高度一致

    private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return position * itemHeight - firstVisibleChildView.top
        }
        return null
    }

有一个header,其他所有Item高度一致

    var headerHeight = 0
    private fun getScrollYDistance(recyclerView: RecyclerView): Int? {
        kotlin.runCatching {
            val layoutManager = recyclerView.layoutManager as LinearLayoutManager
            val position = layoutManager.findFirstVisibleItemPosition()
            if (position == 0) {
                val headerView = layoutManager.findViewByPosition(0)
                headerHeight = headerView!!.height
            }
            val firstVisibleChildView = layoutManager.findViewByPosition(position)
            val itemHeight = firstVisibleChildView!!.height
            return if (position == 0) {
                position * itemHeight - firstVisibleChildView.top
            } else {
                (position - 1) * itemHeight - firstVisibleChildView.top + headerHeight
            }
        }
        return null
    }

有多个header,其他Item一致

   Integer[] headerHeightArray;
    private int getScollYDistance(){
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getRecyclerView().getLayoutManager();
        // 获取第一个可见item的位置
        int position = layoutManager.findFirstVisibleItemPosition();
        // 获取第一个可见item
        View firstVisiableChildView = layoutManager.findViewByPosition(position);
        // 必须考虑有没有Header  预存下所有header的高度
        int headerCount = adapter.getHeaderCount();
        if (headerCount > 0) {
            if (headerHeightArray == null) {
                headerHeightArray = new Integer[headerCount];
            }
            if (position < headerCount) {
                View headerView_i = layoutManager.findViewByPosition(position);
                headerHeightArray[position] = headerView_i.getHeight();
            }
        }
        // 获取第一个可见item的高度
        int itemHeight = firstVisiableChildView.getHeight();
        // 获取第一个可见item的位置
        int distance = 0;
        if (position == 0) {
            distance = position * itemHeight - firstVisiableChildView.getTop();
        } else {
            int allHeaderHeight = 0;
            for (int i = 0; i < Math.min(position,headerCount); i++) {
                allHeaderHeight = allHeaderHeight + headerHeightArray[i];
            }
            distance = (position - Math.min(position,headerCount)) * itemHeight - firstVisiableChildView.getTop() + allHeaderHeight;
        }
        return distance;
    }

注意调用位置:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    getScollYDistance();
                }
            });

试过的一些想法,都有一些问题,有的可以弥补,有的直接玩完

RecyclerView 虽然有getScrollX() 和 getScrollY(), 但是测试发现这两个函数总是返回0,太无语了。因此想到了下面几种方法来实现获取滑动距离:

利用OnScrollListener

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            private int totalDy = ;
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                totalDy -= dy;
            }
        });

如代码所述,totalDy的确保存了 RecyclerView 的滑动距离,但是当我向下滑动 RecyclerView ,之后插入/删除/移动 Item 的时候,totalDy 就变得不精确了;比如删除或者插入新的Item,那么totalDy就不能再回归到 0了。这个可以通过当删除或者插入时来对totalDy进行加减相应的高度。

totalDy = recyclerView.computeVerticalScrollOffset();

然而compute方法计算出的并不是滑动的精确距离,stackOverflow上有答案解释其为 item 的平均高度 * 可见 item 数目,不是我们需要的精确距离。

totalDy = recyclerView.getChildAt().getTop();

依靠第一个item的滑动距离来进行动画的设置,但是根据该方法得出的 totalDy 在滑动到一定程度后清零。

这是因为recyclerViewl.getChildAt(0) 返回的永远是第一个可见的child,不是所有view list 的第一个child,因此这种用法是得不到滑动距离的。

另外下面这三种用法都是等价的,都是获取第一个可见的child:

       LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
       View firstVisiableChildView = this.getChildAt();
       View firstVisiableChildView = layoutManager.getChildAt()
       int position = layoutManager.findFirstVisibleItemPosition();
       View firstVisiableChildView = layoutManager.getChildAt(position)

但是下面这种就不是获取第一个可见的child,而是获得所有view list 的第一个child。但是滑动一段距离后它总是返回null,即第一个child被recycle后,总是返回null。

//Don't use this function to get the first item, it will return null when the first item is recycled.
LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
View child2 = layoutManager.findViewByPosition();

到此这篇关于Android获取RecyclerView滑动距离方法详细讲解的文章就介绍到这了,更多相关Android获取RecyclerView滑动距离内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(Android获取RecyclerView滑动距离方法详细讲解)