【问题标题】:Endless scrolling recyclerview onScrolled not triggered if content is smaller than screen height如果内容小于屏幕高度,则不会触发无限滚动recyclerview onScrolled
【发布时间】:2017-08-11 12:48:20
【问题描述】:

我正在尝试使用 recyclerview 实现无限滚动,它工作正常。但是,我注意到当内容大小小于屏幕高度时,永远不会调用 onScrolled。我想在向下滚动时加载更多内容,但我无法检测到向下滚动手势,因为从未调用过 onScrolled,因此我无法获得 dy 值。我想知道:

1) 在这种情况下如何获取滚动方向 2)这种情况的最佳做法是什么?每次服务电话我都会收到一定数量的物品。如果返回的项目数没有填满屏幕会怎样?

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            int lastVisibleItemPosition, visibleItemCount, totalItemCount;

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

                if(dy>0)
                {
                    visibleItemCount = recyclerLayoutManager.getChildCount();
                    totalItemCount = recyclerLayoutManager.getItemCount();
                    lastVisibleItemPosition = recyclerLayoutManager.findLastVisibleItemPosition();


                    if (lastVisibleItemPosition >= totalItemCount)
                    {

                        if (!loading && dy>0 && moreToload)
                        {
                            loadMore();
                        }                      
                    }
                }

            }
});

谢谢!

【问题讨论】:

  • 尝试加载更多项目到你的 ListView 以使内容大小超过屏幕高度

标签: android scroll android-recyclerview scrollview endlessscroll


【解决方案1】:

onScrolled 回调也会在布局计算后可见项目范围发生变化时被调用。请查看链接here

这意味着它总是在完成将项目加载到回收站视图后调用一次

 @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    visibleItemCount = recyclerLayoutManager.getChildCount();
    totalItemCount = recyclerLayoutManager.getItemCount();
    lastVisibleItemPosition = recyclerLayoutManager.findLastVisibleItemPosition();

    if ((totalItemCount == visibleItemCount) || //This mean you still have space in your screen
        (dy > 0 && !loading && lastVisibleItemPosition >= totalItemCount)) {
        // Call load more here
    }
}

如果服务器没有返回任何项目,recyclerView 将不会更新,默认情况下onScroll 方法不会再次调用,直到您到达 recyclerView 的末尾。

【讨论】:

    【解决方案2】:

    您可以尝试相同的方法,但要使用 RecyclerView.LayoutManager 自定义和处理过度滚动

    @Override
    public int scrollVerticallyBy ( int dx, RecyclerView.Recycler recycler, 
    RecyclerView.State state ) {
       int scrollRange = super.scrollVerticallyBy(dx, recycler, state);
       int overscroll = dx - scrollRange;
       if (overscroll > 0) {
        // bottom overscroll
       } else if (overscroll < 0) {
        // top overscroll
        }
       return scrollRange;
    }
    

    【讨论】:

      【解决方案3】:
      1. 创建一个 LinearLayoutManager 的子类,让您可以监听 onLayoutCompleted() 事件:
      /**
       * This class calls [mCallback] (instance of [OnLayoutCompleteCallback]) when all layout
       * calculations are complete, e.g. following a call to
       * [RecyclerView.Adapter.notifyDataSetChanged()] (or related methods).
       *
       * In a paginated listing, we will decide if load more needs to be called in the said callback.
       */
      class NotifyingLinearLayoutManager(context: Context) : LinearLayoutManager(context, VERTICAL, false) {
          var mCallback: OnLayoutCompleteCallback? = null
      
          override fun onLayoutCompleted(state: RecyclerView.State?) {
              super.onLayoutCompleted(state)
              mCallback?.onLayoutComplete()
          }
      
          fun isLastItemCompletelyVisible() = findLastCompletelyVisibleItemPosition() == itemCount - 1
      
          interface OnLayoutCompleteCallback {
              fun onLayoutComplete()
          }
      }
      
      1. 在您的侦听器中,您可以决定是否需要调用加载更多内容:
      mLayoutManager.mCallback = object : NotifyingLinearLayoutManager.OnLayoutCompleteCallback {
          override fun onLayoutComplete() {
              // here we know that the view has been updated.
              loadMoreIfNeeded()
          }
      }
      
      1. 我的loadMoreIfNeeded() 如下所示:
      private fun loadMoreIfNeeded() {
          if (isAppropriateToLoadMoreItems() && !mLoadMoreRequestFired.getAndSet(true)) {
              mListener.onLoadMore()
          }
      }
      
      private fun isAppropriateToLoadMoreItems() =
              mLoadMoreEnabled && itemCount > 1 && mLayoutManager.isLastItemCompletelyVisible()
      
      
      1. 这些是上一步中使用的以下字段:
      private var mLoadMoreRequestFired = AtomicBoolean(false)
      // makes sure that we fire a single load more call at a time
      
      private var mLoadMoreEnabled = false
      // this flag is used by the footer (containing the ProgressBar) to show or hide it.
      

      【讨论】:

        【解决方案4】:

        只需删除代码中的if(dy &gt; 0)

        最终sn-p

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
            {
                int lastVisibleItemPosition, visibleItemCount, totalItemCount;
        
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy)
                {
                    super.onScrolled(recyclerView, dx, dy);
        
        
                    visibleItemCount = recyclerLayoutManager.getChildCount();
                    totalItemCount = recyclerLayoutManager.getItemCount();
                    lastVisibleItemPosition = recyclerLayoutManager.findLastVisibleItemPosition();
        
        
                     if (lastVisibleItemPosition >= totalItemCount)
                        {
        
                            if (!loading && dy>0 && moreToload)
                            {
                                loadMore();
                            }                      
                        }
                }
        

        });

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-11
          • 2018-11-10
          • 1970-01-01
          • 1970-01-01
          • 2014-09-19
          • 2020-01-31
          • 2019-02-01
          • 2019-10-05
          相关资源
          最近更新 更多