我想把ListView改为RecyclerView。我想在RecyclerView中使用OnScrollListener的onScroll来确定用户是否滚动到列表的末尾。

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


当前回答

我使用了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;
}

其他回答

对于使用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;
    }
}

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

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) {}
}

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

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

下面是我的解决方案,只使用了RecyclerView (RecycerView. view)的抽象类。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.
    }
}
 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 
                        }
                    }          
                }
            });  

Create an abstract class and extends RecyclerView.OnScrollListener public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener { private int previousTotal = 0; private boolean loading = true; private int visibleThreshold; private int firstVisibleItem, visibleItemCount, totalItemCount; private RecyclerView.LayoutManager layoutManager; public EndlessRecyclerOnScrollListener(RecyclerView.LayoutManager layoutManager, int visibleThreshold) { this.layoutManager = layoutManager; this.visibleThreshold = visibleThreshold; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = recyclerView.getChildCount(); totalItemCount = layoutManager.getItemCount(); firstVisibleItem = ((LinearLayoutManager)layoutManager).findFirstVisibleItemPosition(); if (loading) { if (totalItemCount > previousTotal) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { onLoadMore(); loading = true; } } public abstract void onLoadMore();} in activity (or fragment) add addOnScrollListener to recyclerView LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(mLayoutManager); recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager, 3) { @Override public void onLoadMore() { //TODO ... } });