Android Endless List

后端 未结 10 1176
梦如初夏
梦如初夏 2020-11-22 02:52

How can I create a list where when you reach the end of the list I am notified so I can load more items?

相关标签:
10条回答
  • 2020-11-22 03:17

    Best solution so far that I have seen is in FastAdapter library for recycler views. It has a EndlessRecyclerOnScrollListener.

    Here is an example usage: EndlessScrollListActivity

    Once I used it for endless scrolling list I have realised that the setup is a very robust. I'd definitely recommend it.

    0 讨论(0)
  • 2020-11-22 03:21

    You can detect end of the list with help of onScrollListener, working code is presented below:

    @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();
        }
    }
    

    Another way to do that (inside adapter) is as following:

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

    Be aware that this method will be called many times, so you need to add another condition to block multiple calls of addMoreData().

    When you add all elements to the list, please call notifyDataSetChanged() inside yours adapter to update the View (it should be run on UI thread - runOnUiThread)

    0 讨论(0)
  • 2020-11-22 03:23

    Just wanted to contribute a solution that I used for my app.

    It is also based on the OnScrollListener interface, but I found it to have a much better scrolling performance on low-end devices, since none of the visible/total count calculations are carried out during the scroll operations.

    1. Let your ListFragment or ListActivity implement OnScrollListener
    2. 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.

    3. (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>
      
    4. (optional) Finally, remove that loading indicator by calling listView.removeFooterView(yourFooterView) if there are no more items or pages.

    0 讨论(0)
  • 2020-11-22 03:23

    I know its an old question and the Android world has mostly moved on to RecyclerViews, but for anyone interested, you may find this library very interesting.

    It uses the BaseAdapter used with the ListView to detect when the list has been scrolled to the last item or when it is being scrolled away from the last item.

    It comes with an example project(barely 100 lines of Activity code) that can be used to quickly understand how it works.

    Simple usage:

    class Boy{
    
    private String name;
    private double height;
    private int age;
    //Other code
    
    }
    

    An adapter to hold Boy objects would look like:

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

    Notice how the BoysAdapter's getView method returns a call to the EndlessAdapter superclass's getView method. This is 100% essential.

    Now to create the adapter, do:

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

    The loadMore item is a button or other ui element that may be clicked to fetch more data from the url. When placed as described in the code, the adapter knows exactly when to show that button and when to disable it. Just create the button in your xml and place it as shown in the adapter code above.

    Enjoy.

    0 讨论(0)
  • 2020-11-22 03:25

    One solution is to implement an OnScrollListener and make changes (like adding items, etc.) to the ListAdapter at a convenient state in its onScroll method.

    The following ListActivity shows a list of integers, starting with 40, adding items when the user scrolls to the end of the list.

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

    You should obviously use separate threads for long running actions (like loading web-data) and might want to indicate progress in the last list item (like the market or gmail apps do).

    0 讨论(0)
  • 2020-11-22 03:28

    Here is a solution that also makes it easy to show a loading view in the end of the ListView while it's loading.

    You can see the classes here:

    https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Helper to make it possible to use the features without extending from SimpleListViewWithLoadingIndicator.

    https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Listener that starts loading data when the user is about to reach the bottom of the ListView.

    https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView. You can use this class directly or extend from it.

    0 讨论(0)
提交回复
热议问题