Android无尽列表

我如何创建一个列表,当你到达列表的末尾时,我会收到通知,这样我就可以加载更多的项目?

117359 次浏览

一种解决方案是在onScroll方法中实现OnScrollListener并在方便的状态下对ListAdapter进行更改(如添加项等)。

下面的ListActivity显示了一个整数列表,从40开始,当用户滚动到列表的末尾时添加项。

public class Test extends ListActivity implements OnScrollListener {


Aleph0 adapter = new Aleph0();


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(adapter);
getListView().setOnScrollListener(this);
}


public void onScroll(AbsListView view,
int firstVisible, int visibleCount, int totalCount) {


boolean loadMore = /* maybe add a padding */
firstVisible + visibleCount >= totalCount;


if(loadMore) {
adapter.count += visibleCount; // or any other amount
adapter.notifyDataSetChanged();
}
}


public void onScrollStateChanged(AbsListView v, int s) { }


class Aleph0 extends BaseAdapter {
int count = 40; /* starting amount */


public int getCount() { return count; }
public Object getItem(int pos) { return pos; }
public long getItemId(int pos) { return pos; }


public View getView(int pos, View v, ViewGroup p) {
TextView view = new TextView(Test.this);
view.setText("entry " + pos);
return view;
}
}
}

显然,对于长时间运行的操作(如加载web-data),您应该使用单独的线程,并可能希望在最后一个列表项中指示进度(如市场或gmail应用程序)。

你可以在onScrollListener的帮助下检测列表的末尾,工作代码如下所示:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
Log.v(TAG, "onListEnd, extending list");
mPrevTotalItemCount = totalItemCount;
mAdapter.addMoreData();
}
}

另一种方法(内部适配器)如下所示:

    public View getView(int pos, View v, ViewGroup p) {
if(pos==getCount()-1){
addMoreData(); //should be asynctask or thread
}
return view;
}

注意,此方法将被调用多次,因此您需要添加另一个条件来阻止多次调用addMoreData()

当你将所有元素添加到列表中时,请在适配器中调用notifyDataSetChanged ()来更新视图(它应该在UI线程- runOnUiThread上运行)

只是想为我的应用程序贡献一个解决方案。

它也是基于OnScrollListener接口,但我发现它在低端设备上有更好的滚动性能,因为在滚动操作期间没有任何可见/总计数计算。

  1. 让你的ListFragmentListActivity实现OnScrollListener
  2. 将以下方法添加到该类:

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
    int visibleItemCount, int totalItemCount) {
    //leave this empty
    }
    
    
    @Override
    public void onScrollStateChanged(AbsListView listView, int scrollState) {
    if (scrollState == SCROLL_STATE_IDLE) {
    if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
    currentPage++;
    //load more list items:
    loadElements(currentPage);
    }
    }
    }
    

    其中currentPage是应该添加到列表中的数据源页面,而threshold是列表项的数量(从末尾开始计数),如果可见,则应该触发加载过程。例如,如果你将threshold设置为0,用户必须滚动到列表的最末端才能加载更多项

  3. 如你所见,“load-more检查”只在用户停止滚动时被调用。为了提高可用性,你可以通过listView.addFooterView(yourFooterView)在列表的末尾增加一个加载指示器。一个这样的页脚视图的例子:

    <?xml version="1.0" encoding="utf-8"?>
    
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/footer_layout"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="10dp" >
    
    
    <ProgressBar
    android:id="@+id/progressBar1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical" />
    
    
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_toRightOf="@+id/progressBar1"
    android:padding="5dp"
    android:text="@string/loading_text" />
    
    
    </RelativeLayout>
    
  4. (optional) Finally, remove that loading indicator by calling listView.removeFooterView(yourFooterView) if there are no more items or pages.

我一直工作在另一个解决方案非常类似,但是,我使用footerView给可能给用户单击footerView下载更多的元素,我使用一个“菜单”上面所示ListView在父视图的底部,这“菜单”隐藏ListView的底部,所以当listView滚动菜单消失,当滚动状态是闲置,菜单再次出现,但是当用户卷轴listView结束,我“问”知道在这种情况下是否显示footerView,菜单不会出现,用户可以看到footerView来加载更多内容。代码如下:

的问候。

listView.setOnScrollListener(new OnScrollListener() {


@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
if(scrollState == SCROLL_STATE_IDLE) {
if(footerView.isShown()) {
bottomView.setVisibility(LinearLayout.INVISIBLE);
} else {
bottomView.setVisibility(LinearLayout.VISIBLE);
} else {
bottomView.setVisibility(LinearLayout.INVISIBLE);
}
}
}


@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {


}
});

下面是一个解决方案,它也可以很容易地在ListView加载时显示加载视图。

你可以在这里看到这些类:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Helper,使它可以使用功能,而不需要从SimpleListViewWithLoadingIndicator扩展

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java -当用户即将到达ListView的底部时开始加载数据的监听器

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - EndlessListView。你可以直接使用这个类,也可以从它扩展

Ognyan Bankov GitHub我发现了一个简单和工作的解决方案!

它利用Volley HTTP library使Android应用程序的网络更容易,最重要的是,更快。Volley可以通过开放的AOSP存储库获得。

给定的代码演示:

  1. 由HTTP分页请求填充的ListView。
  2. NetworkImageView的使用。
  3. “Endless"带有预读的ListView分页。

为了将来的一致性,i fork Bankov's repo

这个问题的关键是检测load-more事件,启动数据异步请求,然后更新列表。还需要一个带有加载指示器和其他装饰器的适配器。事实上,在一些极端情况下,这个问题非常复杂。只有OnScrollListener实现是不够的,因为有时项目不会填满屏幕。

我写了一个个人包,它支持RecyclerView的无限列表,还提供了一个异步加载器实现AutoPagerFragment,这使得从多页源获取数据非常容易。它可以在自定义事件上将任何页面加载到RecyclerView中,而不仅仅是下一页。

这是地址:https://github.com/SphiaTower/AutoPagerRecyclerManager

可能有点晚了,但下面的解决方案在我的情况下非常有用。 在某种程度上,你所需要做的就是向你的ListView添加一个Footer,并为它创建addOnLayoutChangeListener.

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

例如:

ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview


...


loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.d("Hey!", "Your list has reached bottom");
}
});

当页脚可见时,此事件会触发一次,效果非常好。

到目前为止,我所见过的最好的解决方案是在FastAdapter库中回收器视图。它有EndlessRecyclerOnScrollListener

下面是一个用法示例:EndlessScrollListActivity

一旦我使用它无休止的滚动列表,我已经意识到设置是一个非常强大的。我强烈推荐。

我知道这是一个老问题,Android世界已经大部分转移到RecyclerViews,但对于任何感兴趣的人来说,你可能会发现库非常有趣。

它使用与ListView一起使用的BaseAdapter来检测列表何时已经滚动到最后一项或何时正在从最后一项滚动出去。

它附带了一个示例项目(只有100行活动代码),可以用来快速理解它是如何工作的。

简单的用法:

class Boy{


private String name;
private double height;
private int age;
//Other code


}

一个用于保存Boy对象的适配器看起来像这样:


public class BoysAdapter extends EndlessAdapter<Boy>{








ViewHolder holder = null;




if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent
.getContext());


holder = new ViewHolder();


convertView = inflater.inflate(
R.layout.list_cell, parent, false);




holder.nameView = convertView.findViewById(R.id.cell);


// minimize the default image.
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}


Boy boy = getItem(position);


try {
holder.nameView.setText(boy.getName());


///Other data rendering codes.


} catch (Exception e) {
e.printStackTrace();
}


return super.getView(position,convertView,parent);


}

注意BoysAdapter的getView方法如何返回对EndlessAdapter超类的getView方法的调用。这是100%必要的。

现在要创建适配器,请执行以下操作:

   adapter = new ModelAdapter() {
@Override
public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {


if (moreItemsCouldBeAvailable) {
makeYourServerCallForMoreItems();
} else {
if (loadMore.getVisibility() != View.VISIBLE) {
loadMore.setVisibility(View.VISIBLE);
}
}
}


@Override
public void onScrollAwayFromBottom(int currentIndex) {
loadMore.setVisibility(View.GONE);
}


@Override
public void onFinishedLoading(boolean moreItemsReceived) {
if (!moreItemsReceived) {
loadMore.setVisibility(View.VISIBLE);
}
}
};
loadMore项是一个按钮或其他ui元素,可以点击从url获取更多数据。 当按照代码中描述的位置放置时,适配器确切地知道何时显示该按钮,何时禁用该按钮。只需在xml中创建按钮,并按照上面适配器代码所示的位置放置它

享受。