Android无尽列表

Isa*_*ler 231 android listview list

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

Jos*_*ger 268

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

下面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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,您应该为长时间运行的操作(例如加载Web数据)使用单独的线程,并且可能希望在最后一个列表项中指示进度(如市场或gmail应用程序那样).

  • 我注意到很多使用BaseAdapter的例子.想要提一下,如果您使用的是数据库,请尝试使用SimpleCursorAdapter.当您需要添加到列表中时,更新数据库,获取新游标,并使用SimpleCursorAdapter#changeCursor和notifyDataSetChanged.不需要子类化,并且它比BaseAdapter表现更好(同样,只有在您使用数据库时). (9认同)
  • 这段代码的另一个问题是,对于监听器的多次调用,条件`firstVisible + visibleCount> = totalCount`被多次满足.如果load-more函数是Web请求(很可能是),请添加另一个检查请求是否正在进行.另一方面,检查totalCount是否不等于Previous total count,因为我们不需要对列表中相同数量的项目进行多次请求. (5认同)
  • 呵呵,如果你停止在屏幕中间滚动,这不会触发适配器大小的增加吗?它应该只在实际到达列表底部时加载下一个10. (3认同)
  • 注意 - 我使用了这种方法,但需要在visibleCount为0时添加一个检查.对于每个列表,我得到一个回调到onScroll,其中firstVisible,visibleCount和totalCount都是0,这在技术上符合条件,但不是当我想加载更多. (2认同)

sas*_*oar 94

只是想贡献我用于我的应用程序的解决方案.

它也基于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);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    currentPage应该添加到列表中的数据源页面在哪里,是threshold列表项的数量(从末尾开始计算),如果可见,则应触发加载过程.如果设置threshold0,例如,用户滚动到列表的最末端,以装载更多的物品.

  3. (可选)如您所见,只有在用户停止滚动时才会调用"load-more check".为了提高可用性,您可以通过扩充并在列表末尾添加加载指示符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>
    
    Run Code Online (Sandbox Code Playgroud)
  4. (可选)最后,listView.removeFooterView(yourFooterView)如果没有更多项目或页面,则通过调用删除该加载指示符.

  • 注意:在listview上添加和删除页脚是有问题的(如果在添加页脚之前调用setAdapter,则页脚不显示),我最终直接修改页脚视图的可见性而不删除它. (7认同)

Dar*_*ski 20

您可以在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 除了在`getView`中返回视图之外,做其他事情是不好的做法.例如,您无法保证用户可以查看"pos".它可能只是ListView测量的东西. (7认同)