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


当前回答

你可以在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上运行)

其他回答

在Ognyan Bankov GitHub我发现了一个简单而有效的解决方案!

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

给定的代码演示:

由HTTP分页请求填充的ListView。 NetworkImageView的使用。 “无尽”的ListView分页预读。

为了将来的一致性,我分叉了班科夫的回购。

你可以在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上运行)

我知道这是一个老问题,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中创建按钮,并按照上面适配器代码所示的方式放置它。

享受。

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

下面的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接口,但我发现它在低端设备上的滚动性能要好得多,因为在滚动操作期间不执行任何可见/总计数计算。

Let your ListFragment or ListActivity implement OnScrollListener Add the following methods to that class: @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); } } } where currentPage is the page of your datasource that should be added to your list, and threshold is the number of list items (counted from the end) that should, if visible, trigger the loading process. If you set threshold to 0, for instance, the user has to scroll to the very end of the list in order to load more items. (optional) As you can see, the "load-more check" is only called when the user stops scrolling. To improve usability, you may inflate and add a loading indicator to the end of the list via listView.addFooterView(yourFooterView). One example for such a footer view: <?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> (optional) Finally, remove that loading indicator by calling listView.removeFooterView(yourFooterView) if there are no more items or pages.