检测 ListView 何时到达底部 - onScroll() 或 onScrollStateChanged()?

Detect when ListView has reached the bottom - onScroll() or onScrollStateChanged()?

这似乎是一个已经有很多答案的问题;但是,我找不到通用的方法。 当到达底部时,我正在尝试将数据添加到 ListView;使用 AsyncTask 从 Internet 检索数据。 ListView 已经连接了一个适配器。

因此,在寻找实现此目的的好方法时,我找到了两种不同的方法。

  1. 第一种,onScrollStateChanged()的方法,基本上和this page. However, it use parameters that don't have correspondence in the actual API. At the same time, thislink使用权有关API,但不知道是不是在权方法。我尝试了两个 link 中的第一个,但它有点无聊。调试应用程序,diff 值变化很大,我不知道如何正确插入表达式。另外,我不知道如何修复可以开始检索数据的偏移量;我的意思是,我不想在即将到达底部时执行代码,而是在到达底部之前执行代码。此外,有时即使我们滚动到顶部也会调用它。
  2. 第二种是 onScroll() 方法,在 this answer or, in a different way, in this 代码中使用。我试着调整最后两个代码,但它会导致很多问题,即使我们没有到达列表底部也会加载数据。

那么,哪种方法最好?什么时候以及为什么我应该更喜欢其中之一? 在我的案例中,我应该使用两者中的哪一个?

下面是我在自己的项目中使用的建议的第三种方法的一些代码。我使用适配器的 getView 方法来检测何时到达列表末尾。

public View getView(int position, View convertView, ViewGroup parent) {
    // handle recycling/creating/initializing view
    if(reachedEndOfList(position)) loadMoreData();
    return convertView;
}

private boolean reachedEndOfList(int position) {
    // can check if close or exactly at the end
    return position == getSize() - 1;
}

private void loadMoreData() {
    // Perhaps set flag to indicate you're loading and check flag before proceeding with AsyncTask or whatever
}

您可以使用适配器来检测列表视图何时滚动到底部,就像@darnmason 在上面接受的答案中所做的那样,但我发现有时当列表滚动得非常快时,getView 方法可能不会最后处理适配器中的最后一个位置...可能是因为它仍在渲染一些较早的位置。

这个烦人的效果导致当我滚动到列表底部时淡入视图的按钮有时无法呈现。

下面是带有烦人效果的解决方案,原理上与@darnmason 的解决方案类似:

public abstract class MyAdapter extends BaseAdapter {

public View getView(int position, View convertView, ViewGroup parent) {

//your code for getView here...


    if(position == this.getCount() - 1){
                onScrollToBottom(position);
            }
    else{
                onScrollAwayFromBottom(position);
             }
   return convertView;
}


    public abstract void onScrollToBottom(int bottomIndex);
    public abstract void onScrollAwayFromBottom(int currentIndex);


}

此解决方案检测列表何时滚动到底部以及何时滚动离开底部。

要消除烦人的效果,只需修改如下:

public abstract class MyAdapter extends BaseAdapter {

public View getView(int position, View convertView, ViewGroup parent) {

//your code for getView here...


    if(position == this.getCount() - 1){
                onScrollToBottom(position);
            }
    else{
           AdapterView adapterView = (AdapterView) parent;
                int count = adapterView.getCount();
         if(adapterView.getLastVisiblePosition() == count - 1){
//The adapter was faking it, it is already at the bottom!
                    onScrollToBottom(count - 1);
          }
         else {
//Honestly! The adapter is truly not at the bottom.
                    onScrollAwayFromBottom(position);
               }
             }
   return convertView;
}


    public abstract void onScrollToBottom(int bottomIndex);
    public abstract void onScrollAwayFromBottom(int currentIndex);


}

现在像往常一样调用您的适配器,如下所示:

MyAdapter adapter = new MyAdapter(){

  @Override
            public void onScrollToBottom(int bottomIndex) {
/*loadMore is a button that fades into view when you are not at the bottom of the list so you can tap and load more data*/
                    loadMore.show();

            }

            @Override
            public void onScrollAwayFromBottom(int currentIndex) {
/*loadMore is a button that fades out of view when you are not at the bottom of the list*/
                  loadMore.hide();

            }

}

当以这种方式实现时,适配器在检测列表何时滚动到底部时变得非常有效。

只需要列表中的一点合作!