简体   繁体   English

滚动时检测 RecyclerView 何时到达最底部 position

[英]Detect when RecyclerView reaches the bottom most position while scrolling

I have this code for a RecyclerView.我有一个 RecyclerView 的代码。

    recyclerView = (RecyclerView)rootview.findViewById(R.id.fabric_recyclerView);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.addItemDecoration(new RV_Item_Spacing(5));
    FabricAdapter fabricAdapter=new FabricAdapter(ViewAdsCollection.getFabricAdsDetailsAsArray());
    recyclerView.setAdapter(fabricAdapter);

I need to know when the RecyclerView reaches bottom most position while scrolling.我需要知道滚动时 RecyclerView 何时到达最底部 position。 Is it possible?可能吗? If yes, how?如果是,如何?

there is also a simple way to do it还有一个简单的方法来做到这一点

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);

        if (!recyclerView.canScrollVertically(1)) {
            Toast.makeText(YourActivity.this, "Last", Toast.LENGTH_LONG).show();

        }
    }
});

direction integers: -1 for up, 1 for down, 0 will always return false.方向整数:-1 向上,1 向下,0 将始终返回 false。

Use this code for avoiding repeated calls使用此代码避免重复调用

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) {
                Log.d("-----","end");
                
            }
        }
    });

Just implement a addOnScrollListener() on your recyclerview.只需在您的 recyclerview 上实现 addOnScrollListener() 即可。 Then inside the scroll listener implement the code below.然后在滚动监​​听器内部实现下面的代码。

RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (mIsLoading)
                return;
            int visibleItemCount = mLayoutManager.getChildCount();
            int totalItemCount = mLayoutManager.getItemCount();
            int pastVisibleItems = mLayoutManager.findFirstVisibleItemPosition();
            if (pastVisibleItems + visibleItemCount >= totalItemCount) {
                //End of list
            }
        }
    };

Answer is in Kotlin, it will work in Java.答案是在 Kotlin 中,它将在 Java 中工作。 IntelliJ should convert it for you if you copy and paste.如果您复制和粘贴,IntelliJ 应该为您转换它。

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener(){

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {

        // 3 lines below are not needed.
        Log.d("TAG","Last visible item is: ${gridLayoutManager.findLastVisibleItemPosition()}")
        Log.d("TAG","Item count is: ${gridLayoutManager.itemCount}")
        Log.d("TAG","end? : ${gridLayoutManager.findLastVisibleItemPosition() == gridLayoutManager.itemCount-1}")

        if(gridLayoutManager.findLastVisibleItemPosition() == gridLayoutManager.itemCount-1){
            // We have reached the end of the recycler view.
        }

        super.onScrolled(recyclerView, dx, dy)
    }
})

This will also work for LinearLayoutManager because it has the same methods used above.这也适用于LinearLayoutManager ,因为它具有上面使用的相同方法。 Namely findLastVisibleItemPosition() and getItemCount() ( itemCount in Kotlin).findLastVisibleItemPosition()getItemCount() (Kotlin 中的itemCount )。

After not being satisfied with most the other answers in this thread, I found something I think is better and is not anywhere on here.在对该线程中的大多数其他答案不满意之后,我发现了一些我认为更好的东西,而且这里没有任何地方。

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (!recyclerView.canScrollVertically(1) && dy > 0)
        {
             //scrolled to BOTTOM
        }else if (!recyclerView.canScrollVertically(-1) && dy < 0)
        {
            //scrolled to TOP
        }
    }
});

This is simple and will hit exactly one time under all conditions when you have scrolled to the top or bottom.这很简单,并且当您滚动到顶部或底部时,在所有条件下都会恰好点击一次。

I was not getting a perfect solution by the above answers because it was triggering twice even on onScrolled通过上述答案,我没有得到完美的解决方案,因为即使在onScrolled上它也会触发两次

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
           if( !recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN))
               context?.toast("Scroll end reached")
        }

Alternative solution which I had found some days ago,我几天前发现的替代解决方案,

  rv_repatriations.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            if (!recyclerView.canScrollVertically(RecyclerView.FOCUS_DOWN) && recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE
                && !isLoaded
            ) {
                isLoaded = true
               //do what you want here and after calling the function change the value of boolean
                Log.e("RepatriationFragment", "Scroll end reached")
            }
        }
    })

Using a boolean to ensure that it's not called multiple times when we hit the bottom.使用布尔值来确保当我们触底时它不会被多次调用。

Try This尝试这个

I have used above answers it runs always when you will go at the end of recycler view,我已经使用了上面的答案,当您在回收站视图结束时,它总是运行,

If you want to check only one time whether it is on a bottom or not?如果您只想检查一次它是否在底部? Example:- If I have the list of 10 items whenever I go on the bottom it will display me and again if I scroll top to bottom it will not print again, and if you add more lists and you go there it will again display.示例:-如果我在底部时有 10 个项目的列表,它会显示我,如果我从上到下滚动它不会再次打印,如果你添加更多列表并且你去那里它会再次显示。

Note:- Use this method when you deal with offset in hitting API注意:-当您处理命中 API 的偏移时使用此方法

  1. Create a class named as EndlessRecyclerViewScrollListener创建一个名为 EndlessRecyclerViewScrollListener 的类

     import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener { // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; // The current offset index of data you have loaded private int currentPage = 0; // The total number of items in the dataset after the last load private int previousTotalItemCount = 0; // True if we are still waiting for the last set of data to load. private boolean loading = true; // Sets the starting page index private int startingPageIndex = 0; RecyclerView.LayoutManager mLayoutManager; public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) { this.mLayoutManager = layoutManager; } // public EndlessRecyclerViewScrollListener() { // this.mLayoutManager = layoutManager; // visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); // } public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) { this.mLayoutManager = layoutManager; visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); } public int getLastVisibleItem(int[] lastVisibleItemPositions) { int maxSize = 0; for (int i = 0; i < lastVisibleItemPositions.length; i++) { if (i == 0) { maxSize = lastVisibleItemPositions[i]; } else if (lastVisibleItemPositions[i] > maxSize) { maxSize = lastVisibleItemPositions[i]; } } return maxSize; } // This happens many times a second during a scroll, so be wary of the code you place here. // We are given a few useful parameters to help us work out if we need to load some more data, // but first we check if we are waiting for the previous load to finish. @Override public void onScrolled(RecyclerView view, int dx, int dy) { int lastVisibleItemPosition = 0; int totalItemCount = mLayoutManager.getItemCount(); if (mLayoutManager instanceof StaggeredGridLayoutManager) { int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null); // get maximum element within the list lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions); } else if (mLayoutManager instanceof GridLayoutManager) { lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition(); } else if (mLayoutManager instanceof LinearLayoutManager) { lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); } // If the total item count is zero and the previous isn't, assume the // list is invalidated and should be reset back to initial state if (totalItemCount < previousTotalItemCount) { this.currentPage = this.startingPageIndex; this.previousTotalItemCount = totalItemCount; if (totalItemCount == 0) { this.loading = true; } } // If it's still loading, we check to see if the dataset count has // changed, if so we conclude it has finished loading and update the current page // number and total item count. if (loading && (totalItemCount > previousTotalItemCount)) { loading = false; previousTotalItemCount = totalItemCount; } // If it isn't currently loading, we check to see if we have breached // the visibleThreshold and need to reload more data. // If we do need to reload some more data, we execute onLoadMore to fetch the data. // threshold should reflect how many total columns there are too if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) { currentPage++; onLoadMore(currentPage, totalItemCount, view); loading = true; } } // Call this method whenever performing new searches public void resetState() { this.currentPage = this.startingPageIndex; this.previousTotalItemCount = 0; this.loading = true; } // Defines the process for actually loading more data based on page public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view); }
  2. use this class like this像这样使用这个类

     LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener( linearLayoutManager) { @Override public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { Toast.makeText(getActivity(),"LAst",Toast.LENGTH_LONG).show(); } });

Its running perfect at my end, commnent me if you are getting any issue它在我的最后运行完美,如果您遇到任何问题,请评论我

There is my implementation, it is very useful for StaggeredGridLayout .有我的实现,它对StaggeredGridLayout非常有用。

Usage :用法 :

private EndlessScrollListener scrollListener =
        new EndlessScrollListener(new EndlessScrollListener.RefreshList() {
            @Override public void onRefresh(int pageNumber) {
                //end of the list
            }
        });

rvMain.addOnScrollListener(scrollListener);

Listener implementation :监听器实现:

class EndlessScrollListener extends RecyclerView.OnScrollListener {
private boolean isLoading;
private boolean hasMorePages;
private int pageNumber = 0;
private RefreshList refreshList;
private boolean isRefreshing;
private int pastVisibleItems;

EndlessScrollListener(RefreshList refreshList) {
    this.isLoading = false;
    this.hasMorePages = true;
    this.refreshList = refreshList;
}

@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    StaggeredGridLayoutManager manager =
            (StaggeredGridLayoutManager) recyclerView.getLayoutManager();

    int visibleItemCount = manager.getChildCount();
    int totalItemCount = manager.getItemCount();
    int[] firstVisibleItems = manager.findFirstVisibleItemPositions(null);
    if (firstVisibleItems != null && firstVisibleItems.length > 0) {
        pastVisibleItems = firstVisibleItems[0];
    }

    if (visibleItemCount + pastVisibleItems >= totalItemCount && !isLoading) {
        isLoading = true;
        if (hasMorePages && !isRefreshing) {
            isRefreshing = true;
            new Handler().postDelayed(new Runnable() {
                @Override public void run() {
                    refreshList.onRefresh(pageNumber);
                }
            }, 200);
        }
    } else {
        isLoading = false;
    }
}

public void noMorePages() {
    this.hasMorePages = false;
}

void notifyMorePages() {
    isRefreshing = false;
    pageNumber = pageNumber + 1;
}

interface RefreshList {
    void onRefresh(int pageNumber);
}  }

I was also searching for this question but I didn't find the answer that satisfied me, so I create own realization of recyclerView.我也在寻找这个问题,但我没有找到让我满意的答案,所以我创建了自己的recyclerView实现。

other solutions is less precise then mine.其他解决方案不如我的精确。 for example: if the last item is pretty big (lot of text) then callback of other solutions will come much earlier then recyclerView realy reached bottom.例如:如果最后一项非常大(大量文本),那么其他解决方案的回调将早得多,然后 recyclerView 真正达到底部。

my sollution fix this issue.我的解决方案解决了这个问题。

class CustomRecyclerView: RecyclerView{

    abstract class TopAndBottomListener{
        open fun onBottomNow(onBottomNow:Boolean){}
        open fun onTopNow(onTopNow:Boolean){}
    }


    constructor(c:Context):this(c, null)
    constructor(c:Context, attr:AttributeSet?):super(c, attr, 0)
    constructor(c:Context, attr:AttributeSet?, defStyle:Int):super(c, attr, defStyle)


    private var linearLayoutManager:LinearLayoutManager? = null
    private var topAndBottomListener:TopAndBottomListener? = null
    private var onBottomNow = false
    private var onTopNow = false
    private var onBottomTopScrollListener:RecyclerView.OnScrollListener? = null


    fun setTopAndBottomListener(l:TopAndBottomListener?){
        if (l != null){
            checkLayoutManager()

            onBottomTopScrollListener = createBottomAndTopScrollListener()
            addOnScrollListener(onBottomTopScrollListener)
            topAndBottomListener = l
        } else {
            removeOnScrollListener(onBottomTopScrollListener)
            topAndBottomListener = null
        }
    }

    private fun createBottomAndTopScrollListener() = object :RecyclerView.OnScrollListener(){
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            checkOnTop()
            checkOnBottom()
        }
    }

    private fun checkOnTop(){
        val firstVisible = linearLayoutManager!!.findFirstCompletelyVisibleItemPosition()
        if(firstVisible == 0 || firstVisible == -1 && !canScrollToTop()){
            if (!onTopNow) {
                onTopNow = true
                topAndBottomListener?.onTopNow(true)
            }
        } else if (onTopNow){
            onTopNow = false
            topAndBottomListener?.onTopNow(false)
        }
    }

    private fun checkOnBottom(){
        var lastVisible = linearLayoutManager!!.findLastCompletelyVisibleItemPosition()
        val size = linearLayoutManager!!.itemCount - 1
        if(lastVisible == size || lastVisible == -1 && !canScrollToBottom()){
            if (!onBottomNow){
                onBottomNow = true
                topAndBottomListener?.onBottomNow(true)
            }
        } else if(onBottomNow){
            onBottomNow = false
            topAndBottomListener?.onBottomNow(false)
        }
    }


    private fun checkLayoutManager(){
        if (layoutManager is LinearLayoutManager)
            linearLayoutManager = layoutManager as LinearLayoutManager
        else
            throw Exception("for using this listener, please set LinearLayoutManager")
    }

    private fun canScrollToTop():Boolean = canScrollVertically(-1)
    private fun canScrollToBottom():Boolean = canScrollVertically(1)
}

then in your activity/fragment:然后在您的活动/片段中:

override fun onCreate() {
    customRecyclerView.layoutManager = LinearLayoutManager(context)
}

override fun onResume() {
    super.onResume()
    customRecyclerView.setTopAndBottomListener(this)
}

override fun onStop() {
    super.onStop()
    customRecyclerView.setTopAndBottomListener(null)
}

hope it will hepl someone ;-)希望它会帮助某人;-)

Using Kotlin使用 Kotlin

   recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                if (!recyclerView.canScrollVertically(1)) {
                    Toast.makeText(context, "Last", Toast.LENGTH_LONG).show();
                }
            }
        })

Kotlin Answer科特林答案

You can use this Kotlin function for best practice of bottom scroll following to create infinite or endless scrolling.您可以使用此 Kotlin 函数来实现底部滚动跟随最佳实践,以创建无限无限滚动。

// Scroll listener.
private fun setupListenerPostListScroll() {
    val scrollDirectionDown = 1 // Scroll down is +1, up is -1.
    var currentListSize = 0

    mRecyclerView.addOnScrollListener(
        object : RecyclerView.OnScrollListener() {

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)

                if (!recyclerView.canScrollVertically(scrollDirectionDown)
                    && newState == RecyclerView.SCROLL_STATE_IDLE
                ) {
                    val listSizeAfterLoading = recyclerView.layoutManager!!.itemCount

                    // List has more item.
                    if (currentListSize != listSizeAfterLoading) {
                        currentListSize = listSizeAfterLoading

                        // Get more posts.
                        postListScrollUpAction(listSizeAfterLoading)
                    }
                    else { // List comes limit.
                        showToastMessageShort("No more items.")
                    }
                }
            }
        })
}

I've seen to many responses for this question and I stand that all of them don't give accurate behavior as an outcome.我已经看到很多关于这个问题的回答,我认为他们都没有给出准确的行为作为结果。 However if you follow this approach I'm positive you'll get the best behavior.但是,如果您遵循这种方法,我很肯定您将获得最佳行为。

rvCategories is your RecyclerView rvCategories是你的 RecyclerView

categoriesList is the list passed to your adapter categoriesList是传递给您的适配器的列表

binding.rvCategories.addOnScrollListener(object : RecyclerView.OnScrollListener() {
  override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            val position = (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
            if (position + 1 == categoriesList.size) {
               // END OF RECYCLERVIEW IS REACHED
            } else {
                // END OF RECYCLERVIEW IS NOT REACHED
            }
    }
})

You can use this, if you put 1 thats will be indicated when you stay in end of list, if you want now when you stay in the start of the list you change 1 for -1你可以使用这个,如果你放 1 那将在你停留在列表末尾时显示,如果你现在想要当你停留在列表的开头时,你将 1 更改为 -1

recyclerChat.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            if (!recyclerView.canScrollVertically(1)) {
               
            }
        }
    })

This is my solution after reading all answers in this post.这是我在阅读了这篇文章中的所有答案后的解决方案。 I only want to show loading when the last item is shown at the end of the list and listview length is larger than screen height, meaning if there's only one or two items in the list, won't show the loading .我只想在最后一项显示在列表末尾并且listview长度大于屏幕高度时显示loading ,这意味着如果列表中只有一个或两个项目,则不会显示loading

private var isLoadMoreLoading: Boolean = false

mRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)

        if (!isLoadMoreLoading) {
            if (linearLayoutManager.findLastCompletelyVisibleItemPosition() == (list.size-1)) {
                if (recyclerView.canScrollVertically(-1)) {

                    adapter?.addLoadMoreView()
                    loadMore()
                }
            }
        }
    }
})

private fun loadMore() {
    isLoadMoreLoading = true
    //call loadMore api
}

Because of this linearLayoutManager.findLastCompletelyVisibleItemPosition() == (list.size-1) , we can know last item is shown, but we also need to know listview can scroll or not.由于这个linearLayoutManager.findLastCompletelyVisibleItemPosition() == (list.size-1) ,我们可以知道最后一个项目是否显示,但我们还需要知道 listview 是否可以滚动。

Therefore I added recyclerView.canScrollVertically(-1) .因此我添加了recyclerView.canScrollVertically(-1) Once you hit the bottom of the list, it cannot scroll down anymore.一旦你点击列表的底部,它就不能再向下滚动了。 -1 means list can scroll up. -1表示列表可以向上滚动。 That means listview length is larger than screen height.这意味着listview长度大于屏幕高度。

This answer is in kotlin.这个答案在 kotlin 中。

The most simple way to do it is in the adapter like this:最简单的方法是在这样的适配器中:

@Override
public void onBindViewHolder(HistoryMessageListAdapter.ItemViewHolder holder, int position) {
            if (position == getItemCount()-1){
                listener.onLastItemReached();
            }
        }

Because as soon as the last item is recycled the listener is triggered.因为一旦最后一个项目被回收,监听器就会被触发。

Most of the answers are poorly constructed and have some issues.大多数答案的结构都很差,并且存在一些问题。 One of the common issues is if the user scrolls fast, the end reached block executes multiple times I've found a solution, where the end block runs just 1 single time.一个常见的问题是,如果用户快速滚动,到达结束块会执行多次我找到了一个解决方案,其中结束块只运行 1 次。

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
    if (yourLayoutManager.findLastVisibleItemPosition() ==
          yourLayoutManager.itemCount - 1 && !recyclerView.canScrollVertically(1)) {
                Logger.log("End reached")
                // Do your operations
       }

       super.onScrolled(recyclerView, dx, dy)
 }

PS Sometimes if RecyclerView gets empty, the end listener might get called. PS 有时如果RecyclerView变空,最终的监听器可能会被调用。 As a solution, you can also add this check in the above code.作为解决方案,您还可以在上述代码中添加此检查。

if (recyclerView.adapter?.itemCount!! > 0)

This is my solution:这是我的解决方案:

    val onScrollListener = object : RecyclerView.OnScrollListener() {

    override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
        directionDown = dy > 0
    }

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        if (recyclerView.canScrollVertically(1).not()
                && state != State.UPDATING
                && newState == RecyclerView.SCROLL_STATE_IDLE
                && directionDown) {
               state = State.UPDATING
            // TODO do what you want  when you reach bottom, direction
            // is down and flag for non-duplicate execution
        }
    }
}

We can use Interface for get the position我们可以使用接口来获取位置

Interface : Create an Interface for listener接口:为监听器创建一个接口

public interface OnTopReachListener { void onTopReached(int position);}

Activity :活动 :

mediaRecycleAdapter = new MediaRecycleAdapter(Class.this, taskList); recycle.setAdapter(mediaRecycleAdapter); mediaRecycleAdapter.setOnSchrollPostionListener(new OnTopReachListener() {
@Override
public void onTopReached(int position) {
    Log.i("Position","onTopReached "+position);  
}
});

Adapter :适配器 :

public void setOnSchrollPostionListener(OnTopReachListener topReachListener) {
    this.topReachListener = topReachListener;}@Override public void onBindViewHolder(MyViewHolder holder, int position) {if(position == 0) {
  topReachListener.onTopReached(position);}}

My solution for horizontal LinearLayoutManager (Kotlin): 我的水平LinearLayoutManager(Kotlin)解决方案:

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                            override fun onScrolled(recyclerView: RecyclerView, dx:Int, dy: Int) {
                                super.onScrolled(recyclerView, dx, dy)

                            if (dx == 0 && !recyclerView.canScrollHorizontally(1)) {
                                //add here your code
                                recyclerView.removeOnScrollListener(this)//remove this listener to prevent leaks
                            }
                        }
                    })

recyclerView.layoutManager?.scrollToPosition(recyclerView.adapter?.itemCount?.minus(1)!!)//scroll to last item position to trigger OnScrollListener

Use this method after declaring and initialising your recyclerView with adapter在使用适配器声明和初始化您的 recyclerView 后使用此方法

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
              
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
               
                if(dy > 0){ // Scrolling Down
                 

**Look at the condition inside if, this is how you can check, either you have scrolled till last element of your recyclerView or not.**

//------------------------------------------------------------------------------

                        LinearLayoutManager linearLayoutManager =
                                (LinearLayoutManager) recyclerView.getLayoutManager();

                        if (linearLayoutManager != null &&
                                linearLayoutManager.findLastCompletelyVisibleItemPosition() ==
                                        recyclerViewList.size() - 1) {
                            //bottom of list!
} 
//------------------------------------------------------------------------------                  
                    
}else if(dy < 0){
                    // Scrolling Up
                   
                }

            }
        });

After a long search, I found the prefect solution, that only scrolls to bottom when you want to, and also maintains the smooth scroll behavior you get by using a ListAdapter:经过长时间的搜索,我找到了完美的解决方案,它只在您需要时滚动到底部,并且还保持了您通过使用 ListAdapter 获得的平滑滚动行为:

    adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            super.onItemRangeInserted(positionStart, itemCount)

            scrollToBottomIfUserIsAtTheBottom(linearLayoutManager, positionStart)
        }
    })

    private fun scrollToBottomIfUserIsAtTheBottom(linearLayout: LinearLayoutManager, positionStart: Int) {
        val messageCount = adapter.itemCount
        val lastVisiblePosition = linearLayout.findLastCompletelyVisibleItemPosition()
        if (lastVisiblePosition == -1 ||
            (positionStart >= (messageCount - 1) &&
                lastVisiblePosition == (positionStart - 1))) 
        {
            recyclerView.scrollToPosition(positionStart)
        }
    }

A few notes:一些注意事项:

  • If you use a list adapter and you add a new item to the list each update, you must create a new list each time for the smooth scroll to work.如果您使用列表适配器并在每次更新时向列表中添加一个新项目,则每次都必须创建一个新列表才能使平滑滚动起作用。
  • Don't use smoothScrollToPosition with the ListAdapter.不要将smoothScrollToPosition与 ListAdapter 一起使用。 It ruins the ListAdapter "smoothier" behavior that happens when the diff works good and it detects that the change between old and new list is in a newly added item.它破坏了 ListAdapter 的“更平滑”行为,这种行为在 diff 运行良好时发生,并且它检测到新旧列表之间的变化是在新添加的项目中。
  • linearLayoutManager is adapter.layoutManager as LinearLayoutManager linearLayoutManager 是adapter.layoutManager as LinearLayoutManager

Try this,试试这个,

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            int visibleItemCount = recyclerView.getLayoutManager().getChildCount();
            int totalItemCount = recyclerView.getLayoutManager().getItemCount();
            int firstVisibleItem = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();

            final int lastItem = firstVisibleItem + visibleItemCount;
            if(lastItem == totalItemCount) {
                if(previousLast != lastItem) {
                    previousLast = lastItem;
                    load();
                }
            }
        }
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM