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

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


当前回答

我是这样做的,简单而简短:

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
    {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy)
        {
            if(!recyclerView.canScrollVertically(1) && dy != 0)
            {
                // Load more results here

            }
        }
    });

其他回答

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

这个解决方案对我来说非常有效。

//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);

大多数答案是假设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.
    }
}

我的答案是一个改良版的努尔。我从一个ListView,在那里我有EndlessScrollListener(你可以很容易地在SO上找到许多答案)到一个RecyclerView,所以我想要一个endlessrecyscrolllistener轻松地更新我过去的监听器。

下面是代码,希望能有所帮助:

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

}

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