it-swarm.com.de

Android-Endlosliste

Wie kann ich eine Liste erstellen, bei der ich benachrichtigt werde, wenn Sie das Ende der Liste erreicht haben, um weitere Elemente laden zu können? 

228
Isaac Waller

Eine Lösung besteht darin, eine OnScrollListener zu implementieren und Änderungen an der ListAdapter in einem geeigneten Zustand in ihrer onScroll-Methode vorzunehmen (z. B. Elemente hinzufügen usw.).

Die folgende ListActivity zeigt eine Liste von Ganzzahlen, beginnend mit 40, und fügt Elemente hinzu, wenn der Benutzer an das Ende der Liste blättert.

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

Sie sollten natürlich separate Threads für lange ausgeführte Aktionen verwenden (z. B. das Laden von Webdaten). Möglicherweise möchten Sie den Fortschritt des letzten Listenelements anzeigen (wie dies bei Market- oder Google Mail-Apps der Fall ist).

268
Josef Pfleger

Ich wollte nur eine Lösung beitragen, die ich für meine App verwendet habe.

Es basiert ebenfalls auf der OnScrollListener-Schnittstelle, aber ich habe festgestellt, dass es auf Low-End-Geräten eine viel bessere Bildlaufleistung bietet, da während der Bildlaufoperationen keine der sichtbaren Gesamtzählungen durchgeführt wird.

  1. Lassen Sie Ihre ListFragment oder ListActivityOnScrollListener implementieren
  2. Fügen Sie dieser Klasse die folgenden Methoden hinzu:

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

    dabei ist currentPage die Seite Ihrer Datenquelle, die Ihrer Liste hinzugefügt werden soll, und threshold die Anzahl der Listenelemente (ab Ende gezählt), die den Ladevorgang auslösen sollen, wenn sie sichtbar sind. Wenn Sie beispielsweise threshold auf 0 setzen, muss der Benutzer bis zum Ende der Liste blättern, um weitere Elemente laden zu können.

  3. (optional) Wie Sie sehen, wird der "load-more check" nur aufgerufen, wenn der Benutzer den Bildlauf stoppt. Um die Benutzerfreundlichkeit zu verbessern, können Sie mit listView.addFooterView(yourFooterView) einen Ladeindikator hinzufügen und am Ende der Liste hinzufügen. Ein Beispiel für eine solche Fußzeile:

    <?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) Zum Schluss entfernen Sie das Ladekennzeichen, indem Sie listView.removeFooterView(yourFooterView) aufrufen, wenn keine weiteren Elemente oder Seiten vorhanden sind.

93
saschoar

Sie können das Ende der Liste mit Hilfe von onScrollListener erkennen. Der folgende Arbeitscode wird angezeigt:

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

Eine andere Möglichkeit, dies (innerhalb des Adapters) zu tun, ist wie folgt:

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

Beachten Sie, dass diese Methode mehrmals aufgerufen wird. Sie müssen also eine weitere Bedingung hinzufügen, um mehrere Aufrufe von addMoreData() zu blockieren.

Wenn Sie der Liste alle Elemente hinzufügen, rufen Sie bitte notifyDataSetChanged () in Ihrem Adapter auf, um die Ansicht zu aktualisieren (sie sollte auf dem UI-Thread ausgeführt werden - runOnUiThread ).

20

Bei Ognyan Bankov GitHub habe ich eine einfache und funktionierende Lösung gefunden! 

Es verwendet das Volley HTTP library , das die Vernetzung für Android-Apps einfacher und vor allem schneller macht. Volley ist über das offene AOSP-Repository verfügbar.

Der angegebene Code zeigt:

  1. ListView, das mit HTTP-paginierten Anforderungen gefüllt ist.
  2. Verwendung von NetworkImageView.
  3. "Endlose" ListView-Paginierung mit Vorauslesen.

Für die zukünftige Konsistenz i gegabeltes Repo von Bankov .

4
oikonomopo

Hier ist eine Lösung, mit der es auch einfach ist, eine Ladeansicht am Ende der ListView anzuzeigen, während sie geladen wird.

Sie können die Klassen hier sehen:

https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.Java - Helper um die Verwendung der Funktionen zu ermöglichen, ohne von SimpleListViewWithLoadingIndicator erweitert zu werden.

https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.Java - Listener Dadurch beginnt das Laden von Daten, wenn der Benutzer das Ende der ListView erreicht.

https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.Java - The EndlessListView. Sie können diese Klasse direkt verwenden oder daraus erweitern.

2

Vielleicht etwas spät, aber die folgende Lösung ist in meinem Fall sehr nützlich. In gewisser Weise müssen Sie lediglich eine Footer zu Ihrer ListView hinzufügen und dafür addOnLayoutChangeListener erstellen.

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

Zum Beispiel:

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

Dieses Ereignis wird einmal ausgelöst, wenn eine Fußzeile sichtbar wird und wie ein Zauber wirkt.

1
tehcpu

Die beste Lösung, die ich bisher gesehen habe, ist in FastAdapter library für Recycler-Ansichten. Es hat eine EndlessRecyclerOnScrollListener

Hier ein Beispiel für eine Verwendung: EndlessScrollListActivity

Nachdem ich es für endlose Bildlauflisten verwendet hatte, wurde mir klar, dass das Setup sehr robust ist. Ich würde es auf jeden Fall empfehlen.

0

Ich habe in einer anderen Lösung gearbeitet, die dem sehr ähnlich ist, aber ich verwende eine footerView, um dem Benutzer die Möglichkeit zu geben, weitere Elemente herunterzuladen, die auf footerView klicken. Ich verwende ein "Menü", das wird über der ListView angezeigt, und im unteren Bereich der übergeordneten Ansicht verdeckt dieses "Menü" die Unterseite der ListView. Wenn also mit listView gescrollt wird, verschwindet das Menü und beim Scrollen Wenn der Benutzer bis zum Ende der Option listView blättert, frage ich, ob in diesem Fall die Option footerView angezeigt wird, und das Menü wird nicht angezeigt und der Benutzer kann die footerView sehen, um mehr Inhalt zu laden. Hier der Code:

Grüße.

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) {

    }
});
0
pabloverd

Ich weiß, es ist eine alte Frage und die Android Welt ist größtenteils zu RecyclerViews übergegangen, aber für alle Interessierten ist die this Bibliothek vielleicht sehr interessant.

Es verwendet den BaseAdapter, der mit der ListView verwendet wird, um zu erkennen, wann die Liste zum letzten Element gescrollt wurde oder wann sie vom letzten Element weg gescrollt wird.

Zum Lieferumfang gehört ein Beispielprojekt (kaum 100 Zeilen Aktivitätscode), mit dem Sie schnell verstehen können, wie es funktioniert.

Einfache Bedienung:

class Boy{

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

}

Ein Adapter zum Halten von Boy-Objekten sieht folgendermaßen aus:


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

}

Beachten Sie, wie die getView-Methode von BoysAdapter einen Aufruf an die getView -Methode der EndlessAdapter-Oberklasse zurückgibt. Dies ist zu 100% unerlässlich.

Gehen Sie wie folgt vor, um den Adapter zu erstellen:

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

Das loadMore -Element ist eine Schaltfläche oder ein anderes UI-Element, auf das geklickt werden kann, um weitere Daten aus der URL abzurufen. Wenn der Adapter wie im Code beschrieben platziert ist, weiß er genau, wann diese Schaltfläche angezeigt und wann sie deaktiviert werden muss. Erstellen Sie einfach die Schaltfläche in Ihrer XML und platzieren Sie sie wie im obigen Adaptercode gezeigt.

Genießen.

0
gbenroscience

Der Schlüssel dieses Problems besteht darin, das Ereignis "mehr laden" zu erkennen, eine asynchrone Datenanforderung zu starten und dann die Liste zu aktualisieren. Außerdem wird ein Adapter mit Ladeanzeige und anderen Dekorateuren benötigt. Tatsächlich ist das Problem in einigen Eckfällen sehr kompliziert. Eine OnScrollListener-Implementierung reicht nicht aus, da die Elemente manchmal den Bildschirm nicht ausfüllen.

Ich habe ein persönliches Paket geschrieben, das eine endlose Liste für RecyclerView unterstützt und außerdem eine async-loader-Implementierung AutoPagerFragment zur Verfügung stellt, die es sehr einfach macht, Daten aus einer mehrseitigen Quelle abzurufen. Es kann jede beliebige Seite in eine RecyclerView eines benutzerdefinierten Ereignisses laden, nicht nur die nächste Seite.

Hier ist die Adresse: https://github.com/SphiaTower/AutoPagerRecyclerManager

0
ProtossShuttle