Android Endless List

232

Bagaimana saya bisa membuat daftar di mana ketika Anda mencapai akhir daftar saya diberitahu sehingga saya dapat memuat lebih banyak item?

Isaac Waller
sumber
9
Saya merekomendasikan CommonWare's EndlessAdapter: github.com/commonsguy/cwac-endless . Saya menemukannya dari jawaban ini untuk pertanyaan lain: stackoverflow.com/questions/4667064/… .
Tyler Collier
Saya memerlukan hal yang sama..dapatkah ada satu bantuan? .. stackoverflow.com/questions/28122304/…

Jawaban:

269

Salah satu solusinya adalah mengimplementasikan OnScrollListenerdan membuat perubahan (seperti menambahkan item, dll.) ListAdapterKe kondisi yang nyaman dalam onScrollmetodenya.

Yang berikut ini ListActivitymemperlihatkan daftar bilangan bulat, mulai dengan 40, menambahkan item ketika pengguna menggulir ke akhir daftar.

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

Anda jelas harus menggunakan utas terpisah untuk tindakan jangka panjang (seperti memuat data web) dan mungkin ingin menunjukkan kemajuan dalam item daftar terakhir (seperti yang dilakukan pasar atau aplikasi gmail).

Josef Pfleger
sumber
3
ya, bukankah ini akan memicu peningkatan ukuran adaptor jika Anda akan berhenti menggulir di tengah layar? seharusnya hanya memuat 10 berikutnya ketika benar-benar mencapai daftar bagian bawah.
Matthias
9
Saya melihat banyak contoh seperti ini menggunakan BaseAdapter. Ingin menyebutkan bahwa jika Anda menggunakan database, coba gunakan SimpleCursorAdapter. Ketika Anda perlu menambahkan ke daftar, perbarui database Anda, dapatkan kursor baru, dan gunakan SimpleCursorAdapter # changeCursor bersama dengan notifyDataSetChanged. Tidak diperlukan subklasifikasi, dan berkinerja lebih baik daripada BaseAdapter (sekali lagi, hanya jika Anda menggunakan database).
brack
1
Setelah memanggil notifyDataSetChanged (), itu akan masuk daftar teratas, bagaimana saya bisa mencegahnya?
gambar
2
Catatan - Saya menggunakan pendekatan ini, tetapi perlu menambahkan tanda centang untuk saat terlihatCount adalah 0. Untuk setiap daftar, saya mendapatkan satu panggilan balik ke onScroll di mana firstVisible, visibleCount, dan totalCount semuanya 0, yang secara teknis memenuhi persyaratan, tetapi tidak ketika saya ingin memuat lebih banyak.
Eric Mill
5
Masalah lain dengan kode ini adalah bahwa kondisi firstVisible + visibleCount >= totalCountdipenuhi beberapa kali dengan beberapa panggilan ke pendengar. Jika fungsi load-more adalah permintaan web, (kemungkinan besar itu adalah), tambahkan cek lain untuk melihat apakah permintaan sedang berjalan atau tidak. Di sisi lain, periksa apakah totalCount tidak sama dengan jumlah total Sebelumnya, karena kami tidak perlu beberapa permintaan untuk jumlah item yang sama dalam daftar.
Subin Sebastian
94

Hanya ingin menyumbangkan solusi yang saya gunakan untuk aplikasi saya.

Ini juga didasarkan pada OnScrollListenerantarmuka, tetapi saya menemukan itu memiliki kinerja scrolling yang jauh lebih baik pada perangkat low-end, karena tidak ada perhitungan jumlah terlihat / total dilakukan selama operasi gulir.

  1. Biarkan Anda ListFragmentatau ListActivityimplementasikanOnScrollListener
  2. Tambahkan metode berikut ke kelas itu:

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

    di mana currentPagehalaman sumber data Anda yang harus ditambahkan ke daftar Anda, dan thresholdjumlah item daftar (dihitung dari akhir) yang seharusnya, jika terlihat, memicu proses pemuatan. Jika Anda mengatur thresholdke 0, misalnya, pengguna harus menggulir ke bagian paling akhir daftar untuk memuat lebih banyak item.

  3. (opsional) Seperti yang Anda lihat, "pemeriksaan beban-lebih" hanya dipanggil ketika pengguna berhenti menggulir. Untuk meningkatkan kegunaan, Anda dapat mengembang dan menambahkan indikator pemuatan ke akhir daftar melalui listView.addFooterView(yourFooterView). Salah satu contoh untuk tampilan footer seperti itu:

    <?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. (opsional) Akhirnya, hapus indikator memuat itu dengan menelepon listView.removeFooterView(yourFooterView)jika tidak ada lagi item atau halaman.

saschoar
sumber
Saya mencoba ini tetapi tidak berhasil untuk ListFragment. Bagaimana itu bisa digunakan di ListFragment.
zeeshan
Yah, saya menggunakannya dengan ListFragmentbaik tanpa masalah - cukup ikuti setiap langkah di atas dan Anda akan baik-baik saja;) Atau Anda bisa memberikan pesan kesalahan?
saschoar
Apa yang mungkin Anda lewatkan dijelaskan dalam jawaban SO ini: stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek
7
catatan: menambah dan menghapus footer di listview bermasalah (footer tidak muncul jika setAdapter dipanggil sebelum menambahkan footer), saya akhirnya memodifikasi visibilitas tampilan footer secara langsung tanpa menghapusnya.
dvd
Apa yang harus ditambahkan di loadElements (currentPage) ??? Maksud saya, apakah saya memanggil AsyncTask atau utas saya?
android_developer
20

Anda dapat mendeteksi akhir daftar dengan bantuan onScrollListener , kode kerjanya disajikan di bawah ini:

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

Cara lain untuk melakukan itu (di dalam adaptor) adalah sebagai berikut:

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

Perlu diketahui bahwa metode ini akan dipanggil berkali-kali, jadi Anda perlu menambahkan kondisi lain untuk memblokir beberapa panggilan addMoreData().

Ketika Anda menambahkan semua elemen ke daftar, silakan hubungi notifyDataSetChanged () di dalam adaptor Anda untuk memperbarui tampilan (itu harus dijalankan pada utas UI - runOnUiThread )

Dariusz Bacinski
sumber
7
Merupakan praktik yang buruk untuk melakukan hal-hal lain selain mengembalikan pemandangan getView. Misalnya, Anda tidak dijamin posdilihat oleh pengguna. Mungkin hanya hal-hal pengukuran ListView.
Thomas Ahle
Saya ingin memuat lebih banyak item setelah 10 item digulir. tapi saya perhatikan bahwa memuat dimulai sebelum item ke-10 terlihat berarti pada item ke-9. Jadi bagaimana cara menghentikan ini?
Atul Bhardwaj
4

Pada Ognyan Bankov GitHubsaya menemukan solusi yang sederhana dan berfungsi!

Itu menggunakan Volley HTTP libraryyang membuat jaringan untuk aplikasi Android lebih mudah dan yang paling penting, lebih cepat. Volley tersedia melalui repositori AOSP terbuka.

Kode yang diberikan menunjukkan:

  1. ListView yang diisi oleh permintaan paginasi HTTP.
  2. Penggunaan NetworkImageView.
  3. Pagination ListView "tanpa ujung" dengan baca-depan.

Untuk konsistensi di masa depan saya membayar repo Bankov .

oikonomopo
sumber
2

Berikut ini adalah solusi yang juga memudahkan untuk menampilkan tampilan pemuatan di akhir ListView saat sedang memuat.

Anda dapat melihat kelas di sini:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Pembantu agar memungkinkan untuk menggunakan fitur tanpa memperluas dari SimpleListViewWithLoadingIndicator.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Pendengar yang mulai memuat data saat pengguna akan mencapai bagian bawah ListView.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView. Anda dapat menggunakan kelas ini secara langsung atau memperluas dari itu.

Fernando Camargo
sumber
1

Mungkin sedikit terlambat tetapi solusi berikut ini terjadi sangat berguna dalam kasus saya. Yang perlu Anda lakukan hanyalah menambah ListView Anda Footerdan membuatnya addOnLayoutChangeListener.

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

Sebagai contoh:

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

Acara ini terjadi sekali ketika footer menjadi terlihat dan bekerja seperti pesona.

tehcpu
sumber
0

Kunci dari masalah ini adalah untuk mendeteksi peristiwa yang memuat lebih banyak, memulai permintaan async untuk data dan kemudian memperbarui daftar. Juga diperlukan adaptor dengan indikator memuat dan dekorator lainnya. Bahkan, masalahnya sangat rumit dalam beberapa kasus sudut. Hanya OnScrollListenerimplementasi saja tidak cukup, karena kadang-kadang item tidak memenuhi layar.

Saya telah menulis paket pribadi yang mendukung daftar tanpa akhir RecyclerView, dan juga menyediakan implementasi loader async AutoPagerFragmentyang membuatnya sangat mudah untuk mendapatkan data dari sumber multi-halaman. Itu dapat memuat halaman yang Anda inginkan ke dalam RecyclerViewacara khusus, tidak hanya halaman berikutnya.

Berikut alamatnya: https://github.com/SphiaTower/AutoPagerRecyclerManager

ProtossShuttle
sumber
Tautan rusak.
DSlomer64
0

Solusi terbaik sejauh ini yang saya lihat adalah di perpustakaan FastAdapter untuk pandangan pendaur ulang. Itu memiliki EndlessRecyclerOnScrollListener.

Berikut ini adalah contoh penggunaan: EndlessScrollListActivity

Setelah saya menggunakannya untuk daftar gulir tanpa akhir, saya menyadari bahwa pengaturannya sangat kuat. Saya pasti akan merekomendasikannya.

Shubham Chaudhary
sumber
0

Saya telah bekerja di solusi lain yang sangat mirip dengan itu, tetapi, saya menggunakan footerViewuntuk memberi kemungkinan kepada pengguna mengunduh lebih banyak elemen dengan mengklik footerView, saya menggunakan "menu" yang ditunjukkan di atas ListViewdan di bagian bawah tampilan induk, "menu" ini menyembunyikan bagian bawahnya ListView, jadi, ketika menu listViewbergulir menghilang dan ketika status gulir idle, menu muncul lagi, tetapi ketika pengguna menggulir ke ujung menu listView, saya "meminta" untuk tahu jika footerViewditampilkan dalam kasus itu, menu tidak muncul dan pengguna dapat melihat footerViewuntuk memuat lebih banyak konten. Berikut kodenya:

Salam.

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

    }
});
pabloverd
sumber
0

Saya tahu ini adalah pertanyaan lama dan dunia Android sebagian besar telah beralih ke RecyclerViews, tetapi bagi siapa pun yang tertarik, Anda mungkin menemukan perpustakaan ini sangat menarik.

Ia menggunakan BaseAdapter yang digunakan dengan ListView untuk mendeteksi kapan daftar telah digulir ke item terakhir atau ketika sedang digulir menjauh dari item terakhir.

Itu datang dengan contoh proyek (hampir 100 baris kode aktivitas) yang dapat digunakan untuk dengan cepat memahami cara kerjanya.

Penggunaan sederhana:

class Boy{

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

}

Adaptor untuk menampung objek Boy akan terlihat seperti:


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

}

Perhatikan bagaimana metode getView BoysAdapter mengembalikan panggilan ke metode superclass EndlessAdapter getView. Ini 100% penting.

Sekarang untuk membuat adaptor, lakukan:

   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 loadMoreitem tombol atau elemen ui lain yang mungkin diklik untuk mengambil lebih banyak data dari url. Ketika ditempatkan sebagaimana dijelaskan dalam kode, adaptor tahu persis kapan harus menunjukkan tombol itu dan kapan harus menonaktifkannya. Cukup buat tombol di xml Anda dan letakkan seperti yang ditunjukkan pada kode adaptor di atas.

Nikmati.

ilmu pengetahuan
sumber