Get the sliding distance of RecyclerView

1. Let me talk about the ultimate solution that can be used first. Everyone is anxious to copy it directly. I want to know it later and come back to see it.

  1. No header, and all items have the same height

    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
    }
  1. There is a header, and all other items have the same height

    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
    }
  1. There are multiple headers, other Items are the same

   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;
    }

Note the calling location:

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

2. Some of the ideas I have tried have some problems, some can be made up for, and some can be finished directly

Although RecyclerView has getScrollX() and getScrollY(), the test found that these two functions always return 0, which is too speechless. Therefore, the following methods are thought of to obtain the sliding distance:

  1. Use OnScrollListener

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            private int totalDy = ;

            @Override

            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                totalDy -= dy;

            }

        });

As mentioned in the code, totalDy does save the sliding distance of RecyclerView, but when I slide RecyclerView down and then insert/delete/move Item, totalDy becomes inaccurate; for example, delete or insert a new Item, then totalDy It can no longer return to 0. This can be done by adding or subtracting the corresponding height to totalDy when deleting or inserting.

2.totalDy = recyclerView.computeVerticalScrollOffset();

However, the compute method does not calculate the precise distance of sliding. There is an answer on stackOverflow explaining that it is the average height of the item * the number of visible items, not the precise distance we need.

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

The animation is set based on the sliding distance of the first item, but the totalDy obtained according to this method is cleared after sliding to a certain extent.

This is because recyclerViewl.getChildAt(0) always returns the first visible child, not the first child of all view lists, so this usage cannot get the sliding distance.

In addition, the following three usages are equivalent, and they all get the first visible child:

       LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();

       View firstVisiableChildView = this.getChildAt();

       View firstVisiableChildView = layoutManager.getChildAt()

       int position = layoutManager.findFirstVisibleItemPosition();

       View firstVisiableChildView = layoutManager.getChildAt(position)

But the following is not to get the first visible child, but to get the first child of all view lists. But it always returns null after sliding for a certain distance, that is, after the first child is recycle, it always returns 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();

Guess you like

Origin blog.csdn.net/m0_37707561/article/details/128641390