【问题标题】:How to implement endless list with RecyclerView?如何使用 RecyclerView 实现无限列表?
【发布时间】:2017-05-21 20:13:55
【问题描述】:

我想将ListView 更改为RecyclerView。我想在RecyclerView 中使用OnScrollListeneronScroll 来确定用户是否滚动到列表末尾。

我如何知道用户是否滚动到列表末尾以便我可以从 REST 服务获取新数据?

【问题讨论】:

标签: android listview android-recyclerview material-design onscrolllistener


【解决方案1】:

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setOnScrollListener%28android.support.v7.widget.RecyclerView.OnScrollListener%29 中有一个方法public void setOnScrollListener (RecyclerView.OnScrollListener listener)。使用那个

编辑:

onScrollListener 中覆盖onScrollStateChanged 方法并执行此操作

            boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;

            //loading is used to see if its already loading, you have to manually manipulate this boolean variable
            if (loadMore && !loading) {
                 //end of list reached
            }

【讨论】:

  • 请更具体!如何使用RecyclerView.OnScrollListener 来确定用户滚动到列表末尾?
  • RecyclerView.OnScrollListener 没有 onScroll!您将 AbsListView.OnScrollListener 与 RecyclerView.OnScrollListener 混合使用。
  • 你应该是onScrollStateChanged
  • onScrollStateChanged 将不起作用,因为它只会在您更改滚动状态时调用,而不是在您滚动时调用。
  • @PedroOliveira onScrollStateChanged 是否可以确定用户滚动到最后一项?
【解决方案2】:

好的,我是使用 RecyclerView.Adapter 的onBindViewHolder 方法完成的。

适配器:

public interface OnViewHolderListener {
    void onRequestedLastItem();
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    ...

    if (position == getItemCount() - 1) onViewHolderListener.onRequestedLastItem();
}

片段(或活动)

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    contentView = inflater.inflate(R.layout.comments_list, container, false);
    recyclerView = (RecyclerView) mContentView.findViewById(R.id.my_recycler_view);
    adapter = new Adapter();
    recyclerView.setAdapter(adapter);

    ...

    adapter.setOnViewHolderListener(new Adapter.OnViewHolderListener() {
        @Override
        public void onRequestedLastItem() {
            //TODO fetch new data from webservice
        }
    });
    return contentView;
}

【讨论】:

  • 依赖 onBind 并不是一个好主意。 RecyclerView 缓存视图 + 有一些布局管理器有预缓存东西的方法。我建议设置一个滚动监听器,当滚动监听器停止时,从布局管理器获取最后一个可见的项目位置。如果您使用的是默认布局管理器,它们都有 findLastVisible** 方法。
  • @yigit RecyclerView 会尝试预缓存多远的东西?如果您有 500 个项目,我真的怀疑它会缓存这么远(否则它将只是对性能的巨大浪费)。当它真正开始缓存时(即使我们在 480 元素时),这意味着是时候加载另一个批次了。
  • 它不会 preCache 东西,除非它平滑滚动到很远的位置。在这种情况下,LLM(默认情况下)布局两页而不是一页,以便它可以找到目标视图并减速到它。它确实缓存超出范围的视图。默认这个缓存大小是2,可以通过setItemCacheSize来配置。
  • @yigit 只是在思考问题我不明白缓存如何在这里提出问题;我们只对第一次绑定“最后”项目感兴趣!当布局管理器重新使用已经绑定的缓存视图时,错过对 onBindViewHolder 的调用并不是问题,因为我们有兴趣在列表末尾分页更多数据。对吗?
  • 在我的 FlexibleAdapter 库中,我选择在 onBindViewHolder() 中调用无限滚动,它就像一个魅力。与滚动侦听器相比,该实现很小,并且更易于使用。
【解决方案3】:

我会尝试扩展使用过的LayoutManager(例如LinearLayoutManager)并覆盖scrollVerticallyBy() 方法。首先,我会先调用super,然后检查返回的整数值。如果该值等于0,则达到底部或顶部边框。然后我会使用findLastVisibleItemPosition() 方法来找出到达哪个边界并在需要时加载更多数据。只是一个想法。

此外,您甚至可以从该方法返回您的值,允许过度滚动并显示“加载”指示器。

【讨论】:

    【解决方案4】:

    制作这些变量。

    private int previousTotal = 0;
    private boolean loading = true;
    private int visibleThreshold = 5;
    int firstVisibleItem, visibleItemCount, totalItemCount;
    

    为回收站视图设置滚动。

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
    
            visibleItemCount = mRecyclerView.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
    
            if (loading) {
                if (totalItemCount > previousTotal) {
                    loading = false;
                    previousTotal = totalItemCount;
                }
            }
            if (!loading && (totalItemCount - visibleItemCount) 
                <= (firstVisibleItem + visibleThreshold)) {
                // End has been reached
    
                Log.i("Yaeye!", "end called");
    
                // Do something
    
                loading = true;
            }
        }
    });
    

    注意:确保您使用LinearLayoutManager 作为RecyclerView 的布局管理器。

    LinearLayoutManager mLayoutManager;
    mLayoutManager = new LinearLayoutManager(this);
    mRecyclerView.setLayoutManager(mLayoutManager);
    

    对于网格

    GridLayoutManager mLayoutManager;
    mLayoutManager = new GridLayoutManager(getActivity(), spanCount);
    mRecyclerView.setLayoutManager(mLayoutManager);
    

    尽情享受无尽的卷轴吧! ^.^

    更新: mRecyclerView.setOnScrollListener() 已弃用,只需替换为mRecyclerView.addOnScrollListener(),警告就会消失!您可以从this SO question 阅读更多内容。

    由于 Android 现在正式支持 Kotlin,这里有一个相同的更新 -

    制作 OnScrollListener

    class OnScrollListener(val layoutManager: LinearLayoutManager, val adapter: RecyclerView.Adapter<RecyclerAdapter.ViewHolder>, val dataList: MutableList<Int>) : RecyclerView.OnScrollListener() {
        var previousTotal = 0
        var loading = true
        val visibleThreshold = 10
        var firstVisibleItem = 0
        var visibleItemCount = 0
        var totalItemCount = 0
    
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
    
            visibleItemCount = recyclerView.childCount
            totalItemCount = layoutManager.itemCount
            firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
    
            if (loading) {
                if (totalItemCount > previousTotal) {
                    loading = false
                    previousTotal = totalItemCount
                }
            }
    
            if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
                val initialSize = dataList.size
                updateDataList(dataList)
                val updatedSize = dataList.size
                recyclerView.post { adapter.notifyItemRangeInserted(initialSize, updatedSize) }
                loading = true
            }
        }
    }
    

    并像这样将其添加到您的 RecyclerView

    recyclerView.addOnScrollListener(OnScrollListener(layoutManager, adapter, dataList))
    

    如需完整代码示例,请随时参考this Github repo

    【讨论】:

    • 知道如何将此解决方案与 GridLayoutManager 一起应用吗?由于 findFirstVisibleItemPosition() 方法仅适用于 LinearLayoutManager,我不知道如何使其工作。
    • 附加信息:在这种情况下,使用 visibleItemCount = mLayoutManager.getChildCount(); 的行为与使用 visibleItemCount = mRecyclerView.getChildCount(); 的行为相同。
    • 将代码放在 onScrollStateChanged() 方法中,而不是 onScrolled() 方法中。
    • @toobsco42 你可以使用这个:int[] firstVisibleItemPositions = new int[yourNumberOfColumns]; pastVisiblesItems = layoutManager.findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
    • 什么是 findFirstVisibleItemPosition() 未解决
    【解决方案5】:

    感谢@Kushal,这就是我实现它的方式

    private boolean loading = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;
    
    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (dy > 0) { //check for scroll down
                visibleItemCount = mLayoutManager.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
    
                if (loading) {
                    if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                        loading = false;
                        Log.v("...", "Last Item Wow !");
                        // Do pagination.. i.e. fetch new data
    
                        loading = true;
                    }
                }
            }
        }
    });
    

    别忘了添加

    LinearLayoutManager mLayoutManager;
    mLayoutManager = new LinearLayoutManager(this);
    mRecyclerView.setLayoutManager(mLayoutManager);
    

    【讨论】:

    • 我能为StaggeredGridLayoutManager做什么
    • mLayoutManager.findLastCompletelyVisibleItemPosition()==mLayoutManager.getItemCount()-1怎么样
    • 对于所有findFirstVisibleItemPosition() 未解决的人,您应该将RecyclerView.LayoutManager 更改为LinearLayoutManager
    • 再次发loading = true的条件在哪里?
    • 别忘了在//Do pagination 部分之后添加loading = true。否则此代码将只运行一次,您无法加载更多项目。
    【解决方案6】:

    我在RecyclerView.Adapter 类的onBindViewHolder 方法中使用此逻辑实现了无限滚动类型的实现。

        if (position == mItems.size() - 1 && mCurrentPage <= mTotalPageCount) {
            if (mCurrentPage == mTotalPageCount) {
                mLoadImagesListener.noMorePages();
            } else {
                int newPage = mCurrentPage + 1;
                mLoadImagesListener.loadPage(newPage);
            }
        }
    

    使用此代码,当 RecyclerView 到达最后一项时,它会递增当前页面并在接口上回调,该接口负责从 api 加载更多数据并将新结果添加到适配器。

    如果不清楚,我可以发布更完整的示例?

    【讨论】:

    • 我知道这篇文章真的很老了,但我有点新手,不知道从哪里得到你要比较的变量。 mCurrentPage 和 mTotalPageCount 指的是我假设的您的数据集,而 mItems 是列表项的数组列表,但是我如何找到位置?
    • 你可以在这里看到我是如何实现我的 RecyclerView.Adapter 的:github.com/dominicthomas/FlikrGridRecyclerView/blob/master/app/…
    【解决方案7】:
     recyclerList.setOnScrollListener(new RecyclerView.OnScrollListener() 
                {
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx,int dy)
                    {
                        super.onScrolled(recyclerView, dx, dy); 
                    }
    
                    @Override
                    public void onScrollStateChanged(RecyclerView recyclerView,int newState) 
                    {
                        int totalItemCount = layoutManager.getItemCount();
                        int lastVisibleItem = layoutManager.findLastVisibleItemPosition();
    
                        if (totalItemCount> 1) 
                        {
                            if (lastVisibleItem >= totalItemCount - 1) 
                            {
                                // End has been reached
                                // do something 
                            }
                        }          
                    }
                });  
    

    【讨论】:

    • onScrollStateChanged() 将不起作用,因为它只会在您更改滚动状态时调用,而不是在您滚动时调用。您必须使用onScrolled() 方法。
    【解决方案8】:

    我的答案是 Noor 的修改版。我从ListView 传递到EndlessScrollListener(您可以在SO 的许多答案中轻松找到)到RecyclerView,所以我想要一个EndlessRecyclScrollListener 来轻松更新我过去的听众。

    下面是代码,希望对你有帮助:

    public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener
    {
        // The total number of items in the dataset after the last load
        private int previousTotalItemCount = 0;
        private boolean loading = true;
        private int visibleThreshold = 5;
        int firstVisibleItem, visibleItemCount, totalItemCount;
        private int startingPageIndex = 0;
        private int currentPage = 0;
    
        @Override
        public void onScrolled(RecyclerView mRecyclerView, int dx, int dy)
        {
            super.onScrolled(mRecyclerView, dx, dy);
            LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView
                    .getLayoutManager();
    
            visibleItemCount = mRecyclerView.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
            onScroll(firstVisibleItem, visibleItemCount, totalItemCount);
        }
    
        public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount)
        {
            // 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;
                currentPage++;
            }
    
            // 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.
            if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem +
                    visibleThreshold))
            {
                onLoadMore(currentPage + 1, totalItemCount);
                loading = true;
            }
        }
    
        // Defines the process for actually loading more data based on page
        public abstract void onLoadMore(int page, int totalItemsCount);
    
    }
    

    【讨论】:

    • 您的实现需要 RecyclerView 使用 LinearLeayoutManager。坏主意!
    • @Orri 你能解释一下原因吗?谢谢!
    • 在您的 onScrolled 中,您将 LayoutManager 从 RecyclerView 转换为 LinearLayoutManager。它不适用于 StaggredGridLayout 或其他任何东西。 StagredGridLayout中没有findFirstVisibleItemPosition()。
    • @Orri 感谢您指出这一点!但我不认为这是一个坏主意,因为它对我有用,并且基于赞成票,其他情况:)
    【解决方案9】:

    对我来说,这很简单:

         private boolean mLoading = false;
    
         mList.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
    
                int totalItem = mLinearLayoutManager.getItemCount();
                int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();
    
                if (!mLoading && lastVisibleItem == totalItem - 1) {
                    mLoading = true;
                    // Scrolled to bottom. Do something here.
                    mLoading = false;
                }
            }
        });
    

    注意异步作业:必须在异步作业结束时更改 mLoading。希望对您有所帮助!

    【讨论】:

    • 基本上,经过几天的自我质疑,我找到了这个答案。这是最好的解决方案,imo。
    • 请给recyclerview一些解决方案,loadmore页码通过android
    • getWebServiceData(); mStoresAdapterData.setOnLoadMoreListener(new StoresAdapter.OnLoadMoreListener() { @Override public void onLoadMore() { //add null ,因此适配器将检查 view_type 并在底部显示进度条 storesList.add(null); mStoresAdapterData.notifyItemInserted(storesList.size () - 1); ++pageNumber; getWebServiceData(); } });都一个接一个地调用,最后只有第二页数据可见,请帮忙
    • 我尝试了许多 recyclerView 分页的实现,但没有一个有效,除了这个,你有我的支持,先生
    【解决方案10】:

    如果只想在最后一项完全显示时收到通知,您可以使用View.canScrollVertically()

    这是我的实现:

    public abstract class OnVerticalScrollListener
            extends RecyclerView.OnScrollListener {
    
        @Override
        public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (!recyclerView.canScrollVertically(-1)) {
                onScrolledToTop();
            } else if (!recyclerView.canScrollVertically(1)) {
                onScrolledToBottom();
            } else if (dy < 0) {
                onScrolledUp();
            } else if (dy > 0) {
                onScrolledDown();
            }
        }
    
        public void onScrolledUp() {}
    
        public void onScrolledDown() {}
    
        public void onScrolledToTop() {}
    
        public void onScrolledToBottom() {}
    }
    

    注意:如果你想支持 API recyclerView.getLayoutManager().canScrollVertically()。

    【讨论】:

    • 这是一个伟大而简单的答案!谢谢!
    • 通过检查 !recyclerView.canScrollVertically(-1) 可以使用类似的解决方案进行拉动刷新。
    • 最好的解决方案。谢谢老兄!
    • @LordParsley 谢谢,已更新。这也是 SwipeRefreshLayout 检查拉动刷新的方式之一。
    • @EpicPandaForce 如果您使用RecyclerView,您将再次走运,因为您可以简单地制作View.canScrollVertically() 的静态副本,因为相关方法在RecyclerView 中被标记为public 而不是protected .如果您愿意,还可以扩展 RecyclerView 以重新实现 canScrollVertically()。第三种简单的方法是致电recyclerView.getLayoutManager().canScrollVertically()。在我的回答中编辑。
    【解决方案11】:

    对于使用 StaggeredGridLayoutManager 的人来说,这是我的实现,它适用于我。

     private class ScrollListener extends RecyclerView.OnScrollListener {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    
            firstVivisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVivisibleItems);
    
            if(!recyclerView.canScrollVertically(1) && firstVivisibleItems[0]!=0) {
                loadMoreImages();
            }
    
        }
    
        private boolean loadMoreImages(){
            Log.d("myTag", "LAST-------HERE------");
            return true;
        }
    }
    

    【讨论】:

    • @SudheeshMohan Here 是全类,它很小)在我的项目中,我动态更改跨度计数,它适用于 1 和 2 跨度计数
    • recyclerView.canScrollVertically(1) 会这样做,但它需要 API 14。:(
    【解决方案12】:

    这是另一种方法。它适用于任何布局管理器。

    1. 使适配器类抽象
    2. 然后在适配器类中创建一个抽象方法(例如load())
    3. onBindViewHolder 中检查位置是否为最后并调用 load()
    4. 在您的活动或片段中创建适配器对象时覆盖 load() 函数。
    5. 在重写的加载函数中实现您的 loadmore 调用

    为了详细了解,我写了一篇博文和示例项目,请在此处获取 http://sab99r.com/blog/recyclerview-endless-load-more/

    MyAdapter.java

    public abstract class MyAdapter extends RecyclerView.Adapter<ViewHolder>{
    
            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                //check for last item
                if ((position >= getItemCount() - 1))
                    load();
            }
    
            public abstract void load();
    }
    

    MyActivity.java

    public class MainActivity extends AppCompatActivity {
        List<Items> items;
        MyAdapter adapter;
    
       @Override
        protected void onCreate(Bundle savedInstanceState) {
        ...
        adapter=new MyAdapter(items){
                @Override
                public void load() {
                    //implement your load more here
                    Item lastItem=items.get(items.size()-1);
                    loadMore();
                }
            };
       }
    }
    

    【讨论】:

    • 与解决方案一样,您不必将适配器抽象化,而是可以在适配器中创建一个接口并让您的活动实现它以保持其灵活和优雅,例如:ItemDisplayListener=>onItemDisplayed (整数位置)。这样你就可以在任何位置加载:在 N、N-1、N-2..
    • 我喜欢这个解决方案!无需监听所有滚动事件并进行潜在的昂贵计算
    • @mcwise 添加一个布尔值finished=false;当你到达终点时 make finished=true.. 将当前 if 条件更改为 if ((position >= getItemCount() - 1) && (!finished))
    • 在第一个解决方案的普及下隐藏的优越解决方案的一个很好的例子。很多时候,最后一行将绑定到一个单独的视图类型,用作“正在加载...”横幅。当此视图类型收到绑定调用时,它将设置一个回调,当有更多数据可用时触发数据更改通知。连接滚动监听器的公认答案是浪费,并且可能不适用于其他布局类型。
    • @mcwise 如果用户主动滚动并返回到最后一项,它只会无休止地调用。 onBindViewHolder 每次视图进入屏幕时只调用一次,不会一直调用。
    【解决方案13】:

    我有一个非常详细的示例,说明如何使用 RecyclerView 进行分页。在高层次上,我有一个设置 PAGE_SIZE ,比如说 30。所以我请求 30 个项目,如果我得到 30 个,那么我请求下一页。如果我得到的项目少于 30 个,我标记一个变量以指示已到达最后一页,然后我停止请求更多页面。看看吧,让我知道你的想法。

    https://medium.com/@etiennelawlor/pagination-with-recyclerview-1cb7e66a502b

    【讨论】:

      【解决方案14】:

      虽然接受的答案完美无缺,但下面的解决方案使用 addOnScrollListener,因为 setOnScrollListener 已被弃用,并减少了变量的数量,以及 if 条件。

      final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
      feedsRecyclerView.setLayoutManager(layoutManager);
      
      feedsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
          @Override
          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
              super.onScrolled(recyclerView, dx, dy);
      
              if (dy > 0) {   
                  if ((layoutManager.getChildCount() + layoutManager.findFirstVisibleItemPosition()) >= layoutManager.getItemCount()) {
                      Log.d("TAG", "End of list");
                      //loadMore();
                  }
              }
          }
      });
      

      【讨论】:

      • 有时我的 loadMore() 方法在 onScrolled() 中调用了三次,知道为什么它被调用三次以及如何停止多次调用它。
      • dy>0 总是假的
      • @ved 那是因为滚动有 3 种状态:滚动、滚动、空闲。你选择一个合适的。
      【解决方案15】:

      检查这个每件事都有详细的解释: Pagination using RecyclerView From A to Z

          mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
          @Override
          public void onScrollStateChanged(RecyclerView recyclerView,
                                           int newState) {
              super.onScrollStateChanged(recyclerView, newState);
          }
      
          @Override
          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
              super.onScrolled(recyclerView, dx, dy);
              int visibleItemCount = mLayoutManager.getChildCount();
              int totalItemCount = mLayoutManager.getItemCount();
              int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();
      
              if (!mIsLoading && !mIsLastPage) {
                  if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                          && firstVisibleItemPosition >= 0) {
                      loadMoreItems();
                  }
              }
          }
      })
      

      loadMoreItems():

      private void loadMoreItems() {
          mAdapter.removeLoading();
          //load data here from the server
      
          // in case of success
          mAdapter.addData(data);
          // if there might be more data
          mAdapter.addLoading();
      }
      

      在我的适配器中:

      private boolean mIsLoadingFooterAdded = false;
      
      public void addLoading() {
          if (!mIsLoadingFooterAdded) {
              mIsLoadingFooterAdded = true;
              mLineItemList.add(new LineItem());
              notifyItemInserted(mLineItemList.size() - 1);
          }
      }
      
      public void removeLoading() {
          if (mIsLoadingFooterAdded) {
              mIsLoadingFooterAdded = false;
              int position = mLineItemList.size() - 1;
              LineItem item = mLineItemList.get(position);
      
              if (item != null) {
                  mLineItemList.remove(position);
                  notifyItemRemoved(position);
              }
          }
      }
      
      public void addData(List<YourDataClass> data) {
      
          for (int i = 0; i < data.size(); i++) {
              YourDataClass yourDataObject = data.get(i);
              mLineItemList.add(new LineItem(yourDataObject));
              notifyItemInserted(mLineItemList.size() - 1);
          }
      }
      

      【讨论】:

      • 该链接可能包含答案,但请尝试在您的帖子中的链接中解释一些重要部分。
      【解决方案16】:

      我让你接近我。适合我。

      希望对你有帮助。

      /**
       * Created by Daniel Pardo Ligorred on 03/03/2016.
       */
      public abstract class BaseScrollListener extends RecyclerView.OnScrollListener {
      
          protected RecyclerView.LayoutManager layoutManager;
      
          public BaseScrollListener(RecyclerView.LayoutManager layoutManager) {
      
              this.layoutManager = layoutManager;
      
              this.init();
          }
      
          @Override
          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
      
              super.onScrolled(recyclerView, dx, dy);
      
              this.onScroll(recyclerView, this.getFirstVisibleItem(), this.layoutManager.getChildCount(), this.layoutManager.getItemCount(), dx, dy);
          }
      
          private int getFirstVisibleItem(){
      
              if(this.layoutManager instanceof LinearLayoutManager){
      
                  return ((LinearLayoutManager) this.layoutManager).findFirstVisibleItemPosition();
              } else if (this.layoutManager instanceof StaggeredGridLayoutManager){
      
                  int[] spanPositions = null; //Should be null -> StaggeredGridLayoutManager.findFirstVisibleItemPositions makes the work.
      
                  try{
      
                      return ((StaggeredGridLayoutManager) this.layoutManager).findFirstVisibleItemPositions(spanPositions)[0];
                  }catch (Exception ex){
      
                      // Do stuff...
                  }
              }
      
              return 0;
          }
      
          public abstract void init();
      
          protected abstract void onScroll(RecyclerView recyclerView, int firstVisibleItem, int visibleItemCount, int totalItemCount, int dx, int dy);
      
      }
      

      【讨论】:

        【解决方案17】:

        这些答案都不会考虑列表是否太小。

        这是我一直在使用的一段代码,它在 RecycleViews 上双向工作。

        @Override
            public boolean onTouchEvent(MotionEvent motionEvent) {
        
                if (recyclerViewListener == null) {
                    return super.onTouchEvent(motionEvent);
                }
        
                /**
                 * If the list is too small to scroll.
                 */
                if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                    if (!canScrollVertically(1)) {
                        recyclerViewListener.reachedBottom();
                    } else if (!canScrollVertically(-1)) {
                        recyclerViewListener.reachedTop();
                    }
                }
        
                return super.onTouchEvent(motionEvent);
            }
        
            public void setListener(RecyclerViewListener recycleViewListener) {
                this.recyclerViewListener = recycleViewListener;
                addOnScrollListener(new OnScrollListener() {
        
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
        
                        if (recyclerViewListener == null) {
                            return;
                        }
        
                        recyclerViewListener.scrolling(dy);
        
                        if (!canScrollVertically(1)) {
                            recyclerViewListener.reachedBottom();
                        } else if (!canScrollVertically(-1)) {
                            recyclerViewListener.reachedTop();
                        }
                    }
        
                });
            }
        

        【讨论】:

          【解决方案18】:

          我在网上使用AsyncListUtil 的解决方案说: 请注意,该类使用单线程加载数据,因此适合从磁盘等辅助存储加载数据,但不适合从网络加载数据。 但我正在使用 odata 来读取数据并且工作正常。 我错过了我的示例数据实体和网络方法。 我只包括示例适配器。

          public class AsyncPlatoAdapter extends RecyclerView.Adapter {
          
              private final AsyncPlatoListUtil mAsyncListUtil;
              private final MainActivity mActivity;
              private final RecyclerView mRecyclerView;
              private final String mFilter;
              private final String mOrderby;
              private final String mExpand;
          
              public AsyncPlatoAdapter(String filter, String orderby, String expand, RecyclerView recyclerView, MainActivity activity) {
                  mFilter = filter;
                  mOrderby = orderby;
                  mExpand = expand;
                  mRecyclerView = recyclerView;
                  mActivity = activity;
                  mAsyncListUtil = new AsyncPlatoListUtil();
          
              }
          
              @Override
              public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                  View itemView = LayoutInflater.from(parent.getContext()).
                          inflate(R.layout.plato_cardview, parent, false);
          
                  // Create a ViewHolder to find and hold these view references, and
                  // register OnClick with the view holder:
                  return new PlatoViewHolderAsync(itemView, this);
              }
          
              @Override
              public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                  final Plato item = mAsyncListUtil.getItem(position);
                  PlatoViewHolderAsync vh = (PlatoViewHolderAsync) holder;
                  if (item != null) {
                      Integer imagen_id = item.Imagen_Id.get();
                      vh.getBinding().setVariable(BR.plato, item);
                      vh.getBinding().executePendingBindings();
                      vh.getImage().setVisibility(View.VISIBLE);
                      vh.getProgress().setVisibility(View.GONE);
                      String cacheName = null;
                      String urlString = null;
                      if (imagen_id != null) {
                          cacheName = String.format("imagenes/imagen/%d", imagen_id);
                          urlString = String.format("%s/menusapi/%s", MainActivity.ROOTPATH, cacheName);
                      }
                      ImageHelper.downloadBitmap(mActivity, vh.getImage(), vh.getProgress(), urlString, cacheName, position);
                  } else {
                      vh.getBinding().setVariable(BR.plato, item);
                      vh.getBinding().executePendingBindings();
                      //show progress while loading.
                      vh.getImage().setVisibility(View.GONE);
                      vh.getProgress().setVisibility(View.VISIBLE);
                  }
              }
          
              @Override
              public int getItemCount() {
                  return mAsyncListUtil.getItemCount();
              }
          
              public class AsyncPlatoListUtil extends AsyncListUtil<Plato> {
                  /**
                   * Creates an AsyncListUtil.
                   */
                  public AsyncPlatoListUtil() {
                      super(Plato.class, //my data class
                              10, //page size
                              new DataCallback<Plato>() {
                                  @Override
                                  public int refreshData() {
                                      //get count calling ../$count ... odata endpoint
                                      return countPlatos(mFilter, mOrderby, mExpand, mActivity);
                                  }
          
                                  @Override
                                  public void fillData(Plato[] data, int startPosition, int itemCount) {
                                      //get items from odata endpoint using $skip and $top
                                      Platos p = loadPlatos(mFilter, mOrderby, mExpand, startPosition, itemCount, mActivity);
                                      for (int i = 0; i < Math.min(itemCount, p.value.size()); i++) {
                                          data[i] = p.value.get(i);
                                      }
          
                                  }
                              }, new ViewCallback() {
                                  @Override
                                  public void getItemRangeInto(int[] outRange) {
                                      //i use LinearLayoutManager in the RecyclerView
                                      LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
                                      outRange[0] = layoutManager.findFirstVisibleItemPosition();
                                      outRange[1] = layoutManager.findLastVisibleItemPosition();
                                  }
          
                                  @Override
                                  public void onDataRefresh() {
                                      mRecyclerView.getAdapter().notifyDataSetChanged();
                                  }
          
                                  @Override
                                  public void onItemLoaded(int position) {
                                      mRecyclerView.getAdapter().notifyItemChanged(position);
                                  }
                              });
                      mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                          @Override
                          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                              onRangeChanged();
                          }
                      });
                  }
              }
          }
          

          【讨论】:

            【解决方案19】:

            虽然这个问题有很多答案,但我还是想分享一下我们创建无尽列表视图的经验。我们最近实现了自定义 Carousel LayoutManager,它可以通过无限滚动列表以及直到某个点来循环工作。这是detailed description on GitHub

            我建议你看看这篇关于创建自定义 LayoutManager 的简短但有价值的建议:http://cases.azoft.com/create-custom-layoutmanager-android/

            【讨论】:

              【解决方案20】:

              有一个名为 paginate 的易于使用的库。同时支持 ListView 和 RecyclerView(LinearLayout、GridLayout 和 StaggeredGridLayout)。

              这是 Github 上项目的link

              【讨论】:

                【解决方案21】:

                @kushal @abdulaziz

                为什么不使用这个逻辑呢?

                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    int totalItemCount, lastVisibleItemPosition;
                
                    if (dy > 0) {
                      totalItemCount = _layoutManager.getItemCount();
                      lastVisibleItemPosition = _layoutManager.findLastVisibleItemPosition();
                
                      if (!_isLastItem) {
                        if ((totalItemCount - 1) == lastVisibleItemPosition) {
                          LogUtil.e("end_of_list");
                
                          _isLastItem = true;
                        }
                      }
                    }
                  }
                

                【讨论】:

                • 我的 onScroller() 为单个项目调用了三次,所以我得到了 end_of_list 三次,而我的分页逻辑被调用了三次。如何更正此问题以仅调用一次分页。
                • @ved 这不应该发生。上面的代码确保end_of_list 条件只会被调用一次。标志_isLastItem 是活动中的全局变量,默认值为false。我所做的是在检测到列表末尾后执行后台任务,检索下一页然后通知适配器新数据集,最后再次将_isLastItem设置为false。
                【解决方案22】:

                试试下面:

                import android.support.v7.widget.GridLayoutManager;
                import android.support.v7.widget.LinearLayoutManager;
                import android.support.v7.widget.RecyclerView;
                import android.support.v7.widget.RecyclerView.LayoutManager;
                
                /**
                 * Abstract Endless ScrollListener
                 * 
                 */
                public abstract class EndlessScrollListener extends
                        RecyclerView.OnScrollListener {
                    // The minimum amount of items to have below your current scroll position
                    // before loading more.
                    private int visibleThreshold = 10;
                    // The current offset index of data you have loaded
                    private int currentPage = 1;
                    // True if we are still waiting for the last set of data to load.
                    private boolean loading = true;
                    // The total number of items in the data set after the last load
                    private int previousTotal = 0;
                    private int firstVisibleItem;
                    private int visibleItemCount;
                    private int totalItemCount;
                    private LayoutManager layoutManager;
                
                    public EndlessScrollListener(LayoutManager layoutManager) {
                        validateLayoutManager(layoutManager);
                        this.layoutManager = layoutManager;
                    }
                
                    public EndlessScrollListener(int visibleThreshold,
                            LayoutManager layoutManager, int startPage) {
                        validateLayoutManager(layoutManager);
                        this.visibleThreshold = visibleThreshold;
                        this.layoutManager = layoutManager;
                        this.currentPage = startPage;
                    }
                
                    private void validateLayoutManager(LayoutManager layoutManager)
                            throws IllegalArgumentException {
                        if (null == layoutManager
                                || !(layoutManager instanceof GridLayoutManager)
                                || !(layoutManager instanceof LinearLayoutManager)) {
                            throw new IllegalArgumentException(
                                    "LayoutManager must be of type GridLayoutManager or LinearLayoutManager.");
                        }
                    }
                
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        visibleItemCount = recyclerView.getChildCount();
                        totalItemCount = layoutManager.getItemCount();
                        if (layoutManager instanceof GridLayoutManager) {
                            firstVisibleItem = ((GridLayoutManager) layoutManager)
                                    .findFirstVisibleItemPosition();
                        } else if (layoutManager instanceof LinearLayoutManager) {
                            firstVisibleItem = ((LinearLayoutManager) layoutManager)
                                    .findFirstVisibleItemPosition();
                        }
                        if (loading) {
                            if (totalItemCount > previousTotal) {
                                loading = false;
                                previousTotal = totalItemCount;
                            }
                        }
                        if (!loading
                                && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
                            // End has been reached do something
                            currentPage++;
                            onLoadMore(currentPage);
                            loading = true;
                        }
                    }
                
                    // Defines the process for actually loading more data based on page
                    public abstract void onLoadMore(int page);
                
                }
                

                【讨论】:

                  【解决方案23】:

                  我检测加载事件的方法不是检测滚动,而是监听最后一个视图是否附加。如果附加了最后一个视图,我认为它是加载更多内容的时机。

                  class MyListener implements RecyclerView.OnChildAttachStateChangeListener {
                      RecyclerView mRecyclerView;
                  
                      MyListener(RecyclerView view) {
                          mRecyclerView = view;
                      }
                  
                      @Override
                      public void onChildViewAttachedToWindow(View view) {
                  
                      RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
                      RecyclerView.LayoutManager mgr = mRecyclerView.getLayoutManager();
                      int adapterPosition = mgr.getPosition(view);
                  
                      if (adapterPosition == adapter.getItemCount() - 1) {
                          // last view was attached
                          loadMoreContent();
                      }
                  
                      @Override
                      public void onChildViewDetachedFromWindow(View view) {}
                  }
                  

                  【讨论】:

                    【解决方案24】:

                    大多数答案是假设RecyclerView 使用LinearLayoutManager,或GridLayoutManager,甚至StaggeredGridLayoutManager,或者假设滚动是垂直或水平的,但没有人发布完全通用的答案

                    使用ViewHolder 的适配器显然不是一个好的解决方案。一个适配器可能有超过 1 个 RecyclerView 使用它。它“适应”它们的内容。它应该是 RecyclerView(它是负责当前向用户显示的内容的一类,而不是只负责向RecyclerView 提供内容的适配器)必须通知您的系统需要更多项目(加载)。

                    这是我的解决方案,只使用 RecyclerView 的抽象类(RecycerView.LayoutManager 和 RecycerView.Adapter):

                    /**
                     * Listener to callback when the last item of the adpater is visible to the user.
                     * It should then be the time to load more items.
                     **/
                    public abstract class LastItemListener extends RecyclerView.OnScrollListener {
                    
                        @Override
                        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                          super.onScrolled(recyclerView, dx, dy);
                    
                          // init
                          RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                          RecyclerView.Adapter adapter = recyclerView.getAdapter();
                    
                          if (layoutManager.getChildCount() > 0) {
                            // Calculations..
                            int indexOfLastItemViewVisible = layoutManager.getChildCount() -1;
                            View lastItemViewVisible = layoutManager.getChildAt(indexOfLastItemViewVisible);
                            int adapterPosition = layoutManager.getPosition(lastItemViewVisible);
                            boolean isLastItemVisible = (adapterPosition == adapter.getItemCount() -1);
                    
                            // check
                            if (isLastItemVisible)
                              onLastItemVisible(); // callback
                         }
                       }
                    
                       /**
                        * Here you should load more items because user is seeing the last item of the list.
                        * Advice: you should add a bollean value to the class
                        * so that the method {@link #onLastItemVisible()} will be triggered only once
                        * and not every time the user touch the screen ;)
                        **/
                       public abstract void onLastItemVisible();
                    
                    }
                    
                    
                    // --- Exemple of use ---
                    
                    myRecyclerView.setOnScrollListener(new LastItemListener() {
                        public void onLastItemVisible() {
                             // start to load more items here.
                        }
                    }
                    

                    【讨论】:

                    • 您的答案是正确的,它适用于所有LayoutManagers,但只有一个时刻:将您的计算代码移动到另一个 scrollListener 方法中 - 将其移动到 onScrollStateChanged 而不是 onScrolled。在onScrollStateChanged 只需检查:if(newState == RecyclerView.SCROLL_STATE_IDLE) { // calculation code }
                    • 感谢您的建议,但我认为这不是更好的解决方案。开发人员希望在 recyclerview 停止滚动之前触发其监听器。所以它可能会完成加载新数据项(如果数据存储在本地),甚至在 recyclerview 的末尾添加一个进度条视图持有者,所以当 recyclerview 停止滚动时,它可以在一个循环进度-bar 作为最后一个可见项目。
                    【解决方案25】:

                    我使用 Abdulaziz Noor Answer

                    创建了 LoadMoreRecyclerView

                    LoadMoreRecyclerView

                    public class LoadMoreRecyclerView extends RecyclerView  {
                    
                        private boolean loading = true;
                        int pastVisiblesItems, visibleItemCount, totalItemCount;
                        //WrapperLinearLayout is for handling crash in RecyclerView
                        private WrapperLinearLayout mLayoutManager;
                        private Context mContext;
                        private OnLoadMoreListener onLoadMoreListener;
                    
                        public LoadMoreRecyclerView(Context context) {
                            super(context);
                            mContext = context;
                            init();
                        }
                    
                        public LoadMoreRecyclerView(Context context, @Nullable AttributeSet attrs) {
                            super(context, attrs);
                            mContext = context;
                            init();
                        }
                    
                        public LoadMoreRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
                            super(context, attrs, defStyle);
                            mContext = context;
                            init();
                        }
                    
                        private void init(){
                            mLayoutManager = new WrapperLinearLayout(mContext,LinearLayoutManager.VERTICAL,false);
                            this.setLayoutManager(mLayoutManager);
                            this.setItemAnimator(new DefaultItemAnimator());
                            this.setHasFixedSize(true);
                        }
                    
                        @Override
                        public void onScrolled(int dx, int dy) {
                            super.onScrolled(dx, dy);
                    
                            if(dy > 0) //check for scroll down
                            {
                                visibleItemCount = mLayoutManager.getChildCount();
                                totalItemCount = mLayoutManager.getItemCount();
                                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
                    
                                if (loading)
                                {
                                    if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount)
                                    {
                                        loading = false;
                                        Log.v("...", "Call Load More !");
                                        if(onLoadMoreListener != null){
                                            onLoadMoreListener.onLoadMore();
                                        }
                                        //Do pagination.. i.e. fetch new data
                                    }
                                }
                            }
                        }
                    
                        @Override
                        public void onScrollStateChanged(int state) {
                            super.onScrollStateChanged(state);
                        }
                    
                        public void onLoadMoreCompleted(){
                            loading = true;
                        }
                    
                        public void setMoreLoading(boolean moreLoading){
                            loading = moreLoading;
                        }
                    
                        public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
                            this.onLoadMoreListener = onLoadMoreListener;
                        }
                    }
                    

                    WrapperLinearLayout

                    public class WrapperLinearLayout extends LinearLayoutManager
                    {
                        public WrapperLinearLayout(Context context, int orientation, boolean reverseLayout) {
                            super(context, orientation, reverseLayout);
                        }
                    
                        @Override
                        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
                            try {
                                super.onLayoutChildren(recycler, state);
                            } catch (IndexOutOfBoundsException e) {
                                Log.e("probe", "meet a IOOBE in RecyclerView");
                            }
                        }
                    }
                    

                    //像xml一样添加

                    <your.package.LoadMoreRecyclerView
                        android:id="@+id/recycler_view"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent">
                    </your.package.LoadMoreRecyclerView>
                    

                    OnCreate 或 onViewCreated

                    mLoadMoreRecyclerView = (LoadMoreRecyclerView) view.findViewById(R.id.recycler_view);
                    mLoadMoreRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() {
                                @Override
                                public void onLoadMore() {
                                    callYourService(StartIndex);
                                }
                            });
                    

                    callYourService

                    private void callYourService(){
                        //callyour Service and get response in any List
                    
                        List<AnyModelClass> newDataFromServer = getDataFromServerService();
                        //Enable Load More
                        mLoadMoreRecyclerView.onLoadMoreCompleted();
                    
                        if(newDataFromServer != null && newDataFromServer.size() > 0){
                                StartIndex += newDataFromServer.size();
                    
                                if (newDataFromServer.size() < Integer.valueOf(MAX_ROWS)) {
                                        //StopLoading..
                                       mLoadMoreRecyclerView.setMoreLoading(false);
                                }
                        }
                        else{
                                mLoadMoreRecyclerView.setMoreLoading(false);
                                mAdapter.notifyDataSetChanged();
                        }
                    }
                    

                    【讨论】:

                      【解决方案26】:

                      也可以不使用滚动监听器,仅使用数据模型的纯逻辑来实现。滚动视图需要按位置获取项目以及最大项目数。模型可以有后台逻辑以块的形式获取所需的项目,而不是一个一个地获取,并在后台线程中执行此操作,当数据准备好时通知视图。

                      这种方法允许获取队列优先于最近请求的(当前可见的)项目而不是较旧的(很可能已经滚动离开)提交,控制要使用的并行线程的数量等等。此方法的完整源代码(演示应用程序和可重用库)可在here 获取。

                      【讨论】:

                        【解决方案27】:

                        这个解决方案非常适合我。

                        //Listener    
                        
                        public abstract class InfiniteScrollListener     extendsRecyclerView.OnScrollListener {
                        
                        public static String TAG = InfiniteScrollListener.class.getSimpleName();
                        int firstVisibleItem, visibleItemCount, totalItemCount;
                        private int previousTotal = 0;
                        private boolean loading = true;
                        private int visibleThreshold = 1;
                        private int current_page = 1;
                        
                        private LinearLayoutManager mLinearLayoutManager;
                        
                        public InfiniteScrollListener(LinearLayoutManager linearLayoutManager) {
                            this.mLinearLayoutManager = linearLayoutManager;
                        }
                        
                        @Override
                        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                            super.onScrolled(recyclerView, dx, dy);
                        
                            visibleItemCount = recyclerView.getChildCount();
                            totalItemCount = mLinearLayoutManager.getItemCount();
                            firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
                        
                            if (loading) {
                                if (totalItemCount > previousTotal) {
                                    loading = false;
                                    previousTotal = totalItemCount;
                                }
                            }
                            if (!loading && (totalItemCount - visibleItemCount - firstVisibleItem <= visibleThreshold)) {
                        
                                current_page++;
                        
                                onLoadMore(current_page);
                        
                                loading = true;
                            }
                        }
                        
                        public void resetState() {
                            loading = true;
                            previousTotal = 0;
                            current_page = 1;
                        }
                        
                        public abstract void onLoadMore(int current_page);
                        }
                        
                        //Implementation into fragment 
                         private InfiniteScrollListener scrollListener;
                        
                        scrollListener = new InfiniteScrollListener(manager) {
                                @Override
                                public void onLoadMore(int current_page) {
                                    //Load data
                                }
                            };
                            rv.setLayoutManager(manager);
                            rv.addOnScrollListener(scrollListener);
                        

                        【讨论】:

                          【解决方案28】:

                          @erdna 请参考我下面的代码。可能会对你有所帮助。

                               int firstVisibleItem, visibleItemCount, totalItemCount;
                             recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
                          
                                  @Override
                                  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                                      super.onScrolled(recyclerView, dx, dy);
                          
                                      visibleItemCount = layoutManager.getChildCount();
                                      totalItemCount = layoutManager.getItemCount();
                                      firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
                                      Log.e("firstVisibleItem", firstVisibleItem + "");
                                      Log.e("visibleItemCount", visibleItemCount + "");
                                      Log.e("totalItemCount", totalItemCount + "");
                          
                                      if (page != total_page_index) {
                                          if (loading) {
                                              if ((visibleItemCount + firstVisibleItem) >= totalItemCount) {
                                                  Log.e("page", String.valueOf(page));
                                                  page=page+1;
                                                  new GetSummary().execute(String.valueOf(page), "");
                                                  loading = false;
                                              }
                                          }
                                      }
                          
                                  }
                          
                          
                              });
                          

                          【讨论】:

                            【解决方案29】:

                            借助 Kotlin 扩展函数的强大功能,代码可以看起来更加优雅。把它放在你想要的任何地方(我把它放在 ExtensionFunctions.kt 文件中):

                            /**
                             * WARNING: This assumes the layout manager is a LinearLayoutManager
                             */
                            fun RecyclerView.addOnScrolledToEnd(onScrolledToEnd: () -> Unit){
                            
                                this.addOnScrollListener(object: RecyclerView.OnScrollListener(){
                            
                                    private val VISIBLE_THRESHOLD = 5
                            
                                    private var loading = true
                                    private var previousTotal = 0
                            
                                    override fun onScrollStateChanged(recyclerView: RecyclerView,
                                                                      newState: Int) {
                            
                                        with(layoutManager as LinearLayoutManager){
                            
                                            val visibleItemCount = childCount
                                            val totalItemCount = itemCount
                                            val firstVisibleItem = findFirstVisibleItemPosition()
                            
                                            if (loading && totalItemCount > previousTotal){
                            
                                                loading = false
                                                previousTotal = totalItemCount
                                            }
                            
                                            if(!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)){
                            
                                                onScrolledToEnd()
                                                loading = true
                                            }
                                        }
                                    }
                                })
                            }
                            

                            然后像这样使用它:

                            youRecyclerView.addOnScrolledToEnd {
                                //What you want to do once the end is reached
                            }
                            

                            此解决方案基于 Kushal Sharma 的回答。但是,这要好一些,因为:

                            1. 它使用onScrollStateChanged 而不是onScroll。这更好,因为每次 RecyclerView 中有任何类型的移动时都会调用 onScroll,而仅当 RecyclerView 的状态发生更改时才会调用 onScrollStateChanged。使用 onScrollStateChanged 可以节省 CPU 时间,从而节省电池。
                            2. 由于它使用扩展功能,因此可以在您拥有的任何 RecyclerView 中使用。客户端代码只有 1 行。

                            【讨论】:

                            • 当我拉 SwipeRefreshLayout's setOnRefreshListener the addOnScrolledToEnd is not working 私有内部类 PullToRefresh : SwipeRefreshLayout.OnRefreshListener { override fun onRefresh() { pbViewMore!!.visibility = View.GONE pageCount = 0 courseList.clear() //调用asynctask 这里 srlNoMessageRefreshLayout!!.isRefreshing = false swipeRefreshLayout!!.isRefreshing = false } }
                            • 嘿比特币现金 - ADA 爱好者,我有一个问题。 VISIBLE_THRESHOLD 是您希望 recyclerList 显示的元素数量......对吗?......这是一个限制吗?
                            【解决方案30】:
                            if (layoutManager.findLastCompletelyVisibleItemPosition() == 
                             recyclerAdapter.getItemCount() - 1) {
                                //load more items.
                             }
                            

                            公平而简单。 这将起作用。

                            【讨论】:

                              猜你喜欢
                              • 2019-07-06
                              • 2017-08-16
                              • 1970-01-01
                              • 1970-01-01
                              • 2021-12-05
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多