Bagaimana cara menerapkan daftar tanpa akhir dengan RecyclerView?

346

Saya ingin berubah ListViewmenjadi RecyclerView. Saya ingin menggunakan onScrolldari OnScrollListenerdalam RecyclerViewuntuk menentukan apakah pengguna menggulir ke akhir daftar.

Bagaimana saya tahu jika pengguna menggulir ke bagian akhir daftar sehingga saya bisa mengambil data baru dari layanan REST?

erdna
sumber
Silakan periksa tautan ini. Ini akan membantu Anda .. stackoverflow.com/questions/26293461/…
samsad
32
Silakan baca pertanyaan dengan seksama! Saya tahu bagaimana melakukan ini dengan ListView tetapi BUKAN cara mengimplementasikannya dengan RecycleView .
erdna
bagaimana menerapkan loadmore onscrolllistener di android.data dimuat tetapi diperbarui pada data yang ada tolong bantu saya
Harsha
2
Anda dapat menggunakan perpustakaan ini: github.com/rockerhieu/rv-adapter-endless . Ini didasarkan pada ide cwac-endlessuntuk ListView.
Hieu Rocker

Jawaban:

422

Terima kasih kepada @Kushal dan ini adalah bagaimana saya menerapkannya

private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (dy > 0) { //check for scroll down
            visibleItemCount = mLayoutManager.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

            if (loading) {
                if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                    loading = false;
                    Log.v("...", "Last Item Wow !");
                    // Do pagination.. i.e. fetch new data
                }
            }
        }
    }
});

Jangan lupa menambahkan

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
Abdulaziz Noor
sumber
11
Apa yang bisa saya lakukan untukStaggeredGridLayoutManager
Pratik Butani
16
Bagaimana denganmLayoutManager.findLastCompletelyVisibleItemPosition()==mLayoutManager.getItemCount()-1
laaptu
45
Untuk semua yang findFirstVisibleItemPosition()tidak menyelesaikannya Anda harus berubah RecyclerView.LayoutManagerkeLinearLayoutManager
Amr Mohammed
26
di mana kondisi untuk membuat loading = truelagi?
Bhargav
10
Jangan lupa untuk menambahkan bagian loading = truesetelah //Do pagination. jika tidak, kode ini hanya akan berjalan sekali dan Anda tidak dapat memuat lebih banyak item.
Shaishav Jogani
165

Buat variabel-variabel ini.

private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;

Atur pada Gulir untuk tampilan pendaur ulang.

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        visibleItemCount = mRecyclerView.getChildCount();
        totalItemCount = mLayoutManager.getItemCount();
        firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading && (totalItemCount - visibleItemCount) 
            <= (firstVisibleItem + visibleThreshold)) {
            // End has been reached

            Log.i("Yaeye!", "end called");

            // Do something

            loading = true;
        }
    }
});

Catatan: Pastikan Anda menggunakan LinearLayoutManagersebagai pengelola tata letak untuk RecyclerView.

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

dan untuk kotak

GridLayoutManager mLayoutManager;
mLayoutManager = new GridLayoutManager(getActivity(), spanCount);
mRecyclerView.setLayoutManager(mLayoutManager);

Bersenang-senanglah dengan gulungan tanpa akhir Anda !! ^. ^

Perbarui: mRecyclerView. setOnScrollListener () sudah usang tinggal ganti dengan mRecyclerView.addOnScrollListener()dan peringatan akan hilang! Anda dapat membaca lebih banyak dari pertanyaan SO ini .

Karena Android sekarang secara resmi mendukung Kotlin, ini adalah pembaruan untuk hal yang sama -

Buat OnScrollListener

class OnScrollListener(val layoutManager: LinearLayoutManager, val adapter: RecyclerView.Adapter<RecyclerAdapter.ViewHolder>, val dataList: MutableList<Int>) : RecyclerView.OnScrollListener() {
    var previousTotal = 0
    var loading = true
    val visibleThreshold = 10
    var firstVisibleItem = 0
    var visibleItemCount = 0
    var totalItemCount = 0

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        visibleItemCount = recyclerView.childCount
        totalItemCount = layoutManager.itemCount
        firstVisibleItem = layoutManager.findFirstVisibleItemPosition()

        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false
                previousTotal = totalItemCount
            }
        }

        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            val initialSize = dataList.size
            updateDataList(dataList)
            val updatedSize = dataList.size
            recyclerView.post { adapter.notifyItemRangeInserted(initialSize, updatedSize) }
            loading = true
        }
    }
}

dan tambahkan ke RecyclerView Anda seperti ini

recyclerView.addOnScrollListener(OnScrollListener(layoutManager, adapter, dataList))

Untuk contoh kode lengkap, silakan lihat repo Github ini .

Kushal Sharma
sumber
14
Adakah ide tentang bagaimana menerapkan solusi ini dengan GridLayoutManager? Karena findFirstVisibleItemPosition()metode ini hanya tersedia dengan LinearLayoutManager, saya tidak tahu cara membuatnya bekerja.
MathieuMaree
1
Informasi tambahan: dalam hal ini, menggunakan visibleItemCount = mLayoutManager.getChildCount();berperilaku sama dengan menggunakan visibleItemCount = mRecyclerView.getChildCount();.
Jing Li
3
Tempatkan kode dalam metode onScrollStateChanged () alih-alih metode onScrolled ().
Anirudh
2
@ toobsco42 Anda dapat menggunakan ini:int[] firstVisibleItemPositions = new int[yourNumberOfColumns]; pastVisiblesItems = layoutManager.findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
MathieuMaree
1
Apa ini findFirstVisibleItemPosition () tidak terselesaikan
Suresh Sharma
72

Bagi mereka yang hanya ingin mendapatkan pemberitahuan ketika item terakhir ditampilkan secara total, Anda dapat menggunakannya View.canScrollVertically() .

Inilah implementasi saya:

public abstract class OnVerticalScrollListener
        extends RecyclerView.OnScrollListener {

    @Override
    public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (!recyclerView.canScrollVertically(-1)) {
            onScrolledToTop();
        } else if (!recyclerView.canScrollVertically(1)) {
            onScrolledToBottom();
        } else if (dy < 0) {
            onScrolledUp();
        } else if (dy > 0) {
            onScrolledDown();
        }
    }

    public void onScrolledUp() {}

    public void onScrolledDown() {}

    public void onScrolledToTop() {}

    public void onScrolledToBottom() {}
}

Catatan: Anda dapat menggunakan recyclerView.getLayoutManager().canScrollVertically()jika Anda ingin mendukung API <14.

Hai Zhang
sumber
Ini jawaban yang bagus dan sederhana! Terima kasih!
Andranik
2
Solusi serupa dapat digunakan untuk menarik untuk menyegarkan dengan memeriksa! RecyclerView.canScrollVertically (-1).
LordParsley
Solusi terbaik di luar sana. Terima kasih Bung!
Angmar
1
@ LordParsley Terima kasih, diperbarui. Ini juga salah satu cara SwipeRefreshLayout memeriksa tarik untuk menyegarkan.
Hai Zhang
1
@EpicPandaForce Jika Anda menggunakan RecyclerViewAnda akan beruntung lagi, karena Anda hanya dapat membuat salinan statis View.canScrollVertically()sejak metode terkait ditandai publik, bukan dilindungi RecyclerView. Anda juga dapat memperluas RecyclerViewuntuk menerapkan kembali canScrollVertically()jika Anda mau. Cara ketiga dan sederhana adalah menelepon recyclerView.getLayoutManager().canScrollVertically(). Diedit dalam jawaban saya.
Hai Zhang
67

Ini pendekatan lain. Ini akan bekerja dengan manajer tata letak apa pun.

  1. Buat abstrak kelas Adaptor
  2. Kemudian buat metode abstrak di kelas adaptor (mis. Memuat ())
  3. Di onBindViewHolder periksa posisi apakah terakhir dan panggilan muat ()
  4. Menggantikan fungsi load () saat membuat objek adaptor dalam aktivitas atau fragmen Anda.
  5. Dalam fungsi beban terarah, terapkan panggilan beban Anda

Untuk pemahaman detail saya menulis posting blog dan contoh proyek mendapatkannya di sini http://sab99r.com/blog/recyclerview-endless-load-more/

MyAdapter.java

public abstract class MyAdapter extends RecyclerView.Adapter<ViewHolder>{

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            //check for last item
            if ((position >= getItemCount() - 1))
                load();
        }

        public abstract void load();
}

MyActivity.java

public class MainActivity extends AppCompatActivity {
    List<Items> items;
    MyAdapter adapter;

   @Override
    protected void onCreate(Bundle savedInstanceState) {
    ...
    adapter=new MyAdapter(items){
            @Override
            public void load() {
                //implement your load more here
                Item lastItem=items.get(items.size()-1);
                loadMore();
            }
        };
   }
}
Sabeer Mohammed
sumber
3
Seperti solusinya, Anda tidak harus membuat abstrak adaptor Anda, sebaliknya Anda dapat membuat antarmuka di adaptor Anda dan membuat aktivitas Anda mengimplementasikannya menjaganya agar fleksibel dan elegan, mis: ItemDisplayListener => onItemDisplayed (posisi int). Dengan cara ini Anda dapat memuat di posisi apa pun: di N, N-1, N-2 ..
Samer
1
@mcwise tambahkan boolean finished = false; ketika Anda mencapai akhir make finished = true .. ubah kondisi if saat ini menjadi if ((posisi> = getItemCount () - 1) && (! selesai))
Sabeer Mohammed
1
Ini harus ditandai sebagai jawaban yang benar. Ini elegan dan sederhana.
Greg Ennis
2
Sebuah contoh yang baik dari solusi superior yang terkubur di bawah popularitas solusi pertama. Sangat sering, baris terakhir akan terikat ke viewtype terpisah yang berfungsi sebagai spanduk "Memuat ...". Ketika jenis tampilan ini mendapat panggilan mengikat, itu akan mengatur panggilan balik yang memicu pemberitahuan perubahan data ketika lebih banyak data tersedia. Jawaban yang diterima dari mengaitkan pendengar gulir adalah pemborosan, dan mungkin tidak bekerja untuk jenis tata letak lainnya.
Michael Hays
3
@mcwise hanya akan memanggil tanpa henti jika pengguna secara aktif menggulir ke belakang dan kembali ke item terakhir. onBindViewHolder hanya dipanggil sekali setiap kali tampilan memasuki layar dan tidak akan terus-menerus menyebutnya.
David Liu
18

Jawaban saya adalah versi modifikasi Noor. Saya lulus dariListView tempat saya EndlessScrollListener(yang dapat Anda temukan dengan mudah di banyak jawaban di SO) ke RecyclerViewjadi saya ingin aEndlessRecyclScrollListener dengan mudah memperbarui pendengar masa lalu saya.

Jadi ini kodenya, semoga membantu:

public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener
{
    // The total number of items in the dataset after the last load
    private int previousTotalItemCount = 0;
    private boolean loading = true;
    private int visibleThreshold = 5;
    int firstVisibleItem, visibleItemCount, totalItemCount;
    private int startingPageIndex = 0;
    private int currentPage = 0;

    @Override
    public void onScrolled(RecyclerView mRecyclerView, int dx, int dy)
    {
        super.onScrolled(mRecyclerView, dx, dy);
        LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView
                .getLayoutManager();

        visibleItemCount = mRecyclerView.getChildCount();
        totalItemCount = mLayoutManager.getItemCount();
        firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
        onScroll(firstVisibleItem, visibleItemCount, totalItemCount);
    }

    public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount)
    {
        // If the total item count is zero and the previous isn't, assume the
        // list is invalidated and should be reset back to initial state
        if (totalItemCount < previousTotalItemCount)
        {
            this.currentPage = this.startingPageIndex;
            this.previousTotalItemCount = totalItemCount;
            if (totalItemCount == 0)
            {
                this.loading = true;
            }
        }
        // If it’s still loading, we check to see if the dataset count has
        // changed, if so we conclude it has finished loading and update the current page
        // number and total item count.
        if (loading && (totalItemCount > previousTotalItemCount))
        {
            loading = false;
            previousTotalItemCount = totalItemCount;
            currentPage++;
        }

        // If it isn’t currently loading, we check to see if we have breached
        // the visibleThreshold and need to reload more data.
        // If we do need to reload some more data, we execute onLoadMore to fetch the data.
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem +
                visibleThreshold))
        {
            onLoadMore(currentPage + 1, totalItemCount);
            loading = true;
        }
    }

    // Defines the process for actually loading more data based on page
    public abstract void onLoadMore(int page, int totalItemsCount);

}
Federico Ponzi
sumber
1
Implementasi Anda membutuhkan RecyclerView untuk menggunakan LinearLeayoutManager. Ide buruk!
Orri
@Orri Bisakah Anda jelaskan alasannya? Terima kasih!
Federico Ponzi
1
Di onScrolled, Anda mengaktifkan LayoutManager dari RecyclerView ke LinearLayoutManager. Ini tidak berfungsi untuk StaggredGridLayout atau anthing lain. Tidak ada findFirstVisibleItemPosition () di StaggredGridLayout.
Orri
@Orri Terima kasih telah menunjukkan itu! Tapi saya tidak berpikir itu ide yang buruk, karena itu bekerja untuk saya dan, berdasarkan upvote, kasus-kasus lain :)
Federico Ponzi
10

Bagi saya, ini sangat sederhana:

     private boolean mLoading = false;

     mList.setOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            int totalItem = mLinearLayoutManager.getItemCount();
            int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();

            if (!mLoading && lastVisibleItem == totalItem - 1) {
                mLoading = true;
                // Scrolled to bottom. Do something here.
                mLoading = false;
            }
        }
    });

Hati-hati dengan pekerjaan asinkron: mLading harus diubah pada akhir pekerjaan asinkron. Semoga bermanfaat!

Minh Nguyen
sumber
Saya menemukan jawaban ini setelah beberapa hari mempertanyakan diri saya sendiri, pada dasarnya. Ini solusi terbaik, imo.
wsgeorge
tolong berikan beberapa solusi untuk recyclerview dengan memuat lebih banyak nomor halaman lewat android
Harsha
getWebServiceData (); mStoresAdapterData.setOnLoadMoreListener (StoresAdapter.OnLoadMoreListener () baru {@Override public void onLoadMore () {// tambahkan null, jadi adaptor akan memeriksa bilah view_type dan menampilkan progress bar di bagian bawah storesList.add (null); mStoresAdapterData.notifyItem (toko). () - 1); ++ pageNumber; getWebServiceData ();}}); keduanya memanggil satu demi satu akhirnya data halaman ke-2 hanya dapat dilihat tolong bantu
Harsha
saya mencoba banyak implementasi pagination recyclerView tetapi tidak satupun dari mereka yang bekerja, kecuali yang satu ini, Anda memiliki tuan upvote saya
Mohammed Elrashied
9

Sebagian besar jawaban mengasumsikan RecyclerViewkegunaan a LinearLayoutManager, atau GridLayoutManager, atau bahkan StaggeredGridLayoutManager, atau dengan asumsi bahwa penggulirannya vertikal atau horyzontal, tetapi tidak ada yang memposting jawaban yang sepenuhnya umum .

Menggunakan ViewHolderadaptor jelas bukan solusi yang baik. Adaptor mungkin memiliki lebih dari 1 RecyclerViewmenggunakannya. Itu "menyesuaikan" isinya. Itu harus menjadi Recycler View (yang merupakan satu kelas yang bertanggung jawab atas apa yang saat ini ditampilkan kepada pengguna, dan bukan adaptor yang hanya bertanggung jawab untuk menyediakan konten ke RecyclerView) yang harus memberi tahu sistem Anda bahwa diperlukan lebih banyak item (untuk beban).

Inilah solusi saya, tidak menggunakan apa pun selain kelas-kelas abstrak dari RecyclerView (RecycerView.LayoutManager dan RecycerView.Adapter):

/**
 * Listener to callback when the last item of the adpater is visible to the user.
 * It should then be the time to load more items.
 **/
public abstract class LastItemListener extends RecyclerView.OnScrollListener {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
      super.onScrolled(recyclerView, dx, dy);

      // init
      RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
      RecyclerView.Adapter adapter = recyclerView.getAdapter();

      if (layoutManager.getChildCount() > 0) {
        // Calculations..
        int indexOfLastItemViewVisible = layoutManager.getChildCount() -1;
        View lastItemViewVisible = layoutManager.getChildAt(indexOfLastItemViewVisible);
        int adapterPosition = layoutManager.getPosition(lastItemViewVisible);
        boolean isLastItemVisible = (adapterPosition == adapter.getItemCount() -1);

        // check
        if (isLastItemVisible)
          onLastItemVisible(); // callback
     }
   }

   /**
    * Here you should load more items because user is seeing the last item of the list.
    * Advice: you should add a bollean value to the class
    * so that the method {@link #onLastItemVisible()} will be triggered only once
    * and not every time the user touch the screen ;)
    **/
   public abstract void onLastItemVisible();

}


// --- Exemple of use ---

myRecyclerView.setOnScrollListener(new LastItemListener() {
    public void onLastItemVisible() {
         // start to load more items here.
    }
}
Yairopro
sumber
1
Jawaban Anda benar dan berhasil LayoutManagershanya untuk satu saat: pindahkan kode perhitungan Anda dalam metode scrollListener lain - onScrollStateChangedalih - alih pindahkan onScrolled. Dan onScrollStateChangedcukup periksa:if(newState == RecyclerView.SCROLL_STATE_IDLE) { // calculation code }
Trancer
Terima kasih atas saran Anda, tetapi saya tidak berpikir itu akan menjadi solusi yang lebih baik. Pengembang ingin pendengarnya terpicu bahkan sebelum recyclerview berhenti untuk menggulir. Jadi mungkin selesai memuat item data baru (jika data disimpan secara lokal), atau bahkan menambahkan progress-bar view-holder di akhir recyclerview, jadi ketika recyclerview akan berhenti untuk menggulir, itu bisa berada di lingkaran kemajuan -bar sebagai item yang terlihat terakhir.
Yairopro
6

Meskipun jawaban yang diterima bekerja dengan baik, solusi di bawah ini menggunakan addOnScrollListener karena setOnScrollListener sudah usang, dan mengurangi jumlah variabel, dan jika kondisi.

final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
feedsRecyclerView.setLayoutManager(layoutManager);

feedsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        if (dy > 0) {   
            if ((layoutManager.getChildCount() + layoutManager.findFirstVisibleItemPosition()) >= layoutManager.getItemCount()) {
                Log.d("TAG", "End of list");
                //loadMore();
            }
        }
    }
});
capt.swag
sumber
1
Kadang-kadang metode loadMore () saya dipanggil tiga kali di onScrolled (), Tahu mengapa disebut tiga kali dan bagaimana berhenti memanggilnya berkali-kali.
ved
dy> 0 selalu salah
Dushyant Suthar
@ved Itu karena scrolling memiliki 3 status: scrolling, scrolled, idle. Anda memilih satu yang cocok.
TheRealChx101
5

Meskipun ada begitu banyak jawaban untuk pertanyaan ini, saya ingin berbagi pengalaman kami dalam membuat tampilan daftar tanpa akhir. Kami baru-baru ini mengimplementasikan Manajer Layout Carousel kustom yang dapat bekerja dalam siklus dengan menggulir daftar secara tak terbatas serta hingga titik tertentu. Berikut ini penjelasan terperinci tentang GitHub .

Saya sarankan Anda melihat artikel ini dengan rekomendasi singkat tapi berharga untuk membuat LayoutManagers khusus: http://cases.azoft.com/create-custom-layoutmanager-android/

Vladimir Tchernitski
sumber
5

Dengan kekuatan fungsi ekstensi Kotlin, kode dapat terlihat jauh lebih elegan. Letakkan ini di mana pun Anda inginkan (saya memilikinya di dalam file ExtensionFunctions.kt):

/**
 * WARNING: This assumes the layout manager is a LinearLayoutManager
 */
fun RecyclerView.addOnScrolledToEnd(onScrolledToEnd: () -> Unit){

    this.addOnScrollListener(object: RecyclerView.OnScrollListener(){

        private val VISIBLE_THRESHOLD = 5

        private var loading = true
        private var previousTotal = 0

        override fun onScrollStateChanged(recyclerView: RecyclerView,
                                          newState: Int) {

            with(layoutManager as LinearLayoutManager){

                val visibleItemCount = childCount
                val totalItemCount = itemCount
                val firstVisibleItem = findFirstVisibleItemPosition()

                if (loading && totalItemCount > previousTotal){

                    loading = false
                    previousTotal = totalItemCount
                }

                if(!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)){

                    onScrolledToEnd()
                    loading = true
                }
            }
        }
    })
}

Dan kemudian gunakan seperti ini:

youRecyclerView.addOnScrolledToEnd {
    //What you want to do once the end is reached
}

Solusi ini didasarkan pada jawaban Kushal Sharma. Namun, ini sedikit lebih baik karena:

  1. Itu menggunakan onScrollStateChangedbukan onScroll. Ini lebih baik karena onScrolldipanggil setiap kali ada jenis gerakan di RecyclerView, sedangkan onScrollStateChangedhanya dipanggil ketika keadaan RecyclerView diubah. MenggunakanonScrollStateChanged akan menghemat waktu CPU Anda dan, sebagai akibatnya, baterai.
  2. Karena ini menggunakan Fungsi Ekstensi, ini dapat digunakan di RecyclerView yang Anda miliki. Kode klien hanya 1 baris.
Tiago
sumber
Ketika saya melakukan Tarik SwipeRefreshLayout's setOnRefreshListener the addOnScrolledToEnd is not working kelas dalam pribadi PullToRefresh: SwipeRefreshLayout.OnRefreshListener {override fun onRefresh () {pbViewMore !!. Visibility = View.GONE pageCount = 0 courseList.clear () // memanggil asynctask di sini srlNoMessageRefreshLayoutoutout !! ! .isRefreshing = false}}
Naveen Kumar M
5

Inilah cara saya melakukannya, sederhana dan pendek:

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
    {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy)
        {
            if(!recyclerView.canScrollVertically(1) && dy != 0)
            {
                // Load more results here

            }
        }
    });
John T
sumber
3

OK, saya melakukannya dengan menggunakan metode onBindViewHolder dari RecyclerView.Adapter.

Adaptor:

public interface OnViewHolderListener {
    void onRequestedLastItem();
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    ...

    if (position == getItemCount() - 1) onViewHolderListener.onRequestedLastItem();
}

Fragmen (atau Aktivitas) :

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    contentView = inflater.inflate(R.layout.comments_list, container, false);
    recyclerView = (RecyclerView) mContentView.findViewById(R.id.my_recycler_view);
    adapter = new Adapter();
    recyclerView.setAdapter(adapter);

    ...

    adapter.setOnViewHolderListener(new Adapter.OnViewHolderListener() {
        @Override
        public void onRequestedLastItem() {
            //TODO fetch new data from webservice
        }
    });
    return contentView;
}
erdna
sumber
1
mengandalkan onBind bukanlah ide yang sangat bagus. RecyclerView tidak melihat cache + memiliki beberapa manajer tata letak memiliki sarana untuk melakukan pra-cache hal-hal. Saya akan menyarankan pengaturan pendengar gulir dan ketika pendengar gulir berhenti, dapatkan posisi item terakhir yang terlihat dari pengelola tata letak. Jika Anda menggunakan manajer tata letak default, mereka semua memiliki metode ** findLastVisible **.
yigit
@yigit Seberapa jauh RecyclerView akan mencoba melakukan hal-hal lain? Jika Anda memiliki 500 item, saya benar-benar ragu itu akan melakukan cache sejauh ini (jika tidak, itu hanya akan membuang-buang kinerja). Ketika itu benar-benar akan mulai men-cache (bahkan ketika kita di 480 elemen) itu berarti sudah waktunya untuk memuat batch lain pula.
Alex Orlov
1
Itu melakukan hal-hal preCache ingot kecuali itu lancar bergulir ke posisi yang jauh. Dalam hal ini, LLM (secara default) tata letak dua halaman, bukan satu sehingga dapat menemukan tampilan target dan melambat ke sana. Itu dilihat cache yang keluar batas. Secara default, ukuran cache ini adalah 2 dan dapat dikonfigurasi melalui setItemCacheSize.
yigit
1
@yigit hanya memikirkan masalah, saya tidak melihat bagaimana caching bisa menghadirkan masalah di sini; kami hanya tertarik pada pertama kali item "terakhir" terikat! Kehilangan panggilan ke onBindViewHolder saat manajer tata letak menggunakan kembali tampilan cache yang sudah terikat tidak menjadi masalah ketika kami tertarik untuk mencari lebih banyak data di bagian akhir daftar. Benar?
Greg Ennis
2
Di perpustakaan FlexibleAdapter saya, saya memilih untuk menggunakan scroll tanpa akhir dengan panggilan onBindViewHolder(), itu berfungsi seperti pesona. Implementasinya kecil dibandingkan dengan pendengar gulir dan lebih mudah digunakan.
Davideas
3

Cara saya mendeteksi acara pemuatan bukan untuk mendeteksi pengguliran, tetapi untuk mendengarkan apakah tampilan terakhir dilampirkan. Jika tampilan terakhir dilampirkan, saya menganggapnya sebagai waktu untuk memuat lebih banyak konten.

class MyListener implements RecyclerView.OnChildAttachStateChangeListener {
    RecyclerView mRecyclerView;

    MyListener(RecyclerView view) {
        mRecyclerView = view;
    }

    @Override
    public void onChildViewAttachedToWindow(View view) {

    RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
    RecyclerView.LayoutManager mgr = mRecyclerView.getLayoutManager();
    int adapterPosition = mgr.getPosition(view);

    if (adapterPosition == adapter.getItemCount() - 1) {
        // last view was attached
        loadMoreContent();
    }

    @Override
    public void onChildViewDetachedFromWindow(View view) {}
}
walkice
sumber
2

Saya akan mencoba untuk memperluas metode yang digunakan LayoutManager(misalnya LinearLayoutManager) dan menimpa scrollVerticallyBy(). Pertama, saya akan menelepon superdulu dan kemudian memeriksa kembali nilai integer. Jika nilainya sama dengan 0maka batas bawah atau atas tercapai. Maka saya akan menggunakanfindLastVisibleItemPosition() metode untuk mengetahui batas mana yang tercapai dan memuat lebih banyak data jika diperlukan. Hanya sebuah ide.

Selain itu, Anda bahkan dapat mengembalikan nilai Anda dari metode itu yang memungkinkan overscroll dan menampilkan indikator "memuat".

sergej shafarenka
sumber
2
 recyclerList.setOnScrollListener(new RecyclerView.OnScrollListener() 
            {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx,int dy)
                {
                    super.onScrolled(recyclerView, dx, dy); 
                }

                @Override
                public void onScrollStateChanged(RecyclerView recyclerView,int newState) 
                {
                    int totalItemCount = layoutManager.getItemCount();
                    int lastVisibleItem = layoutManager.findLastVisibleItemPosition();

                    if (totalItemCount> 1) 
                    {
                        if (lastVisibleItem >= totalItemCount - 1) 
                        {
                            // End has been reached
                            // do something 
                        }
                    }          
                }
            });  
Anirudh
sumber
1
onScrollStateChanged()tidak akan berfungsi karena hanya akan dipanggil ketika Anda mengubah status gulungan dan tidak saat Anda sedang menggulir. Anda harus menggunakan onScrolled()metode ini.
mradzinski
2

Saya mencapai implementasi tipe pengguliran tak terbatas menggunakan logika ini dalam onBindViewHoldermetode RecyclerView.Adapterkelas saya .

    if (position == mItems.size() - 1 && mCurrentPage <= mTotalPageCount) {
        if (mCurrentPage == mTotalPageCount) {
            mLoadImagesListener.noMorePages();
        } else {
            int newPage = mCurrentPage + 1;
            mLoadImagesListener.loadPage(newPage);
        }
    }

Dengan kode ini ketika RecyclerView sampai ke item terakhir, ia menambah halaman saat ini dan panggilan balik pada antarmuka yang bertanggung jawab untuk memuat lebih banyak data dari api dan menambahkan hasil baru ke adaptor.

Saya dapat memposting contoh yang lebih lengkap jika ini tidak jelas?

speedynomads
sumber
Saya tahu posting ini benar-benar tua, tapi saya agak pemula dan tidak tahu di mana mendapatkan variabel yang Anda bandingkan. mCurrentPage dan mTotalPageCount mengacu pada kumpulan data Anda, saya berasumsi, dan mItems adalah daftar item daftar array, tetapi bagaimana cara menemukan posisi?
BooleanCheese
Anda dapat melihat bagaimana saya menerapkan RecyclerView saya. Beradaptasi di
speedynomads
2

Untuk orang-orang yang menggunakan StaggeredGridLayoutManager di sini adalah implementasi saya, ini berfungsi untuk saya.

 private class ScrollListener extends RecyclerView.OnScrollListener {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

        firstVivisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVivisibleItems);

        if(!recyclerView.canScrollVertically(1) && firstVivisibleItems[0]!=0) {
            loadMoreImages();
        }

    }

    private boolean loadMoreImages(){
        Log.d("myTag", "LAST-------HERE------");
        return true;
    }
}
Dennis Zinkovski
sumber
@SudheeshMohan Ini adalah kelas penuh, ini kecil) Dalam proyek saya, saya mengubah jumlah secara dinamis, dan Ini akan bekerja untuk jumlah rentang 1 dan 2
Dennis Zinkovski
recyclerView.canScrollVertically (1) akan melakukannya tetapi membutuhkan API 14. :(
Sudheesh Mohan
2

Ada perpustakaan yang mudah digunakan untuk paginate bernama ini . Mendukung ListView dan RecyclerView (LinearLayout, GridLayout dan StaggeredGridLayout).

Berikut ini tautan ke proyek di Github

nonybrighto
sumber
2
  1. Buat kelas abstrak dan rentangkan RecyclerView.OnScrollListener

    public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
    private int previousTotal = 0;
    private boolean loading = true;
    private int visibleThreshold;
    private int firstVisibleItem, visibleItemCount, totalItemCount;
    private RecyclerView.LayoutManager layoutManager;
    
    public EndlessRecyclerOnScrollListener(RecyclerView.LayoutManager layoutManager, int visibleThreshold) {
    this.layoutManager = layoutManager; this.visibleThreshold = visibleThreshold;
    }
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    
    visibleItemCount = recyclerView.getChildCount();
    totalItemCount = layoutManager.getItemCount();
    firstVisibleItem = ((LinearLayoutManager)layoutManager).findFirstVisibleItemPosition();
    
    if (loading) {
        if (totalItemCount > previousTotal) {
            loading = false;
            previousTotal = totalItemCount;
        }
    }
    if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
        onLoadMore();
        loading = true;
    }
      }
    
    public abstract void onLoadMore();}
  2. dalam aktivitas (atau fragmen) tambahkan addOnScrollListener ke recyclerView

    LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager, 3) {
        @Override
        public void onLoadMore() {
            //TODO
            ...
        }
    });
roghayeh hosseini
sumber
1

Saya punya contoh yang cukup rinci tentang cara membuat paginasi dengan RecyclerView. Pada tingkat tinggi, saya memiliki satu set PAGE_SIZE, katakanlah 30. Jadi saya meminta 30 item dan jika saya mendapatkan 30 kembali maka saya meminta halaman berikutnya. Jika saya mendapatkan kurang dari 30 item, saya menandai variabel untuk menunjukkan bahwa halaman terakhir telah tercapai dan kemudian saya berhenti meminta lebih banyak halaman. Lihatlah dan beri tahu saya apa yang Anda pikirkan.

https://medium.com/@etiennelawlor/pagination-with-recyclerview-1cb7e66a502b

toobsco42
sumber
1

Di sini solusi saya menggunakan AsyncListUtil , di web mengatakan: Perhatikan bahwa kelas ini menggunakan utas tunggal untuk memuat data, sehingga cocok untuk memuat data dari penyimpanan sekunder seperti disk, tetapi tidak dari jaringan. tetapi saya menggunakan odata untuk membaca data dan berfungsi dengan baik. Saya kehilangan contoh entitas data dan metode jaringan saya. Saya hanya menyertakan contoh adaptor.

public class AsyncPlatoAdapter extends RecyclerView.Adapter {

    private final AsyncPlatoListUtil mAsyncListUtil;
    private final MainActivity mActivity;
    private final RecyclerView mRecyclerView;
    private final String mFilter;
    private final String mOrderby;
    private final String mExpand;

    public AsyncPlatoAdapter(String filter, String orderby, String expand, RecyclerView recyclerView, MainActivity activity) {
        mFilter = filter;
        mOrderby = orderby;
        mExpand = expand;
        mRecyclerView = recyclerView;
        mActivity = activity;
        mAsyncListUtil = new AsyncPlatoListUtil();

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).
                inflate(R.layout.plato_cardview, parent, false);

        // Create a ViewHolder to find and hold these view references, and
        // register OnClick with the view holder:
        return new PlatoViewHolderAsync(itemView, this);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        final Plato item = mAsyncListUtil.getItem(position);
        PlatoViewHolderAsync vh = (PlatoViewHolderAsync) holder;
        if (item != null) {
            Integer imagen_id = item.Imagen_Id.get();
            vh.getBinding().setVariable(BR.plato, item);
            vh.getBinding().executePendingBindings();
            vh.getImage().setVisibility(View.VISIBLE);
            vh.getProgress().setVisibility(View.GONE);
            String cacheName = null;
            String urlString = null;
            if (imagen_id != null) {
                cacheName = String.format("imagenes/imagen/%d", imagen_id);
                urlString = String.format("%s/menusapi/%s", MainActivity.ROOTPATH, cacheName);
            }
            ImageHelper.downloadBitmap(mActivity, vh.getImage(), vh.getProgress(), urlString, cacheName, position);
        } else {
            vh.getBinding().setVariable(BR.plato, item);
            vh.getBinding().executePendingBindings();
            //show progress while loading.
            vh.getImage().setVisibility(View.GONE);
            vh.getProgress().setVisibility(View.VISIBLE);
        }
    }

    @Override
    public int getItemCount() {
        return mAsyncListUtil.getItemCount();
    }

    public class AsyncPlatoListUtil extends AsyncListUtil<Plato> {
        /**
         * Creates an AsyncListUtil.
         */
        public AsyncPlatoListUtil() {
            super(Plato.class, //my data class
                    10, //page size
                    new DataCallback<Plato>() {
                        @Override
                        public int refreshData() {
                            //get count calling ../$count ... odata endpoint
                            return countPlatos(mFilter, mOrderby, mExpand, mActivity);
                        }

                        @Override
                        public void fillData(Plato[] data, int startPosition, int itemCount) {
                            //get items from odata endpoint using $skip and $top
                            Platos p = loadPlatos(mFilter, mOrderby, mExpand, startPosition, itemCount, mActivity);
                            for (int i = 0; i < Math.min(itemCount, p.value.size()); i++) {
                                data[i] = p.value.get(i);
                            }

                        }
                    }, new ViewCallback() {
                        @Override
                        public void getItemRangeInto(int[] outRange) {
                            //i use LinearLayoutManager in the RecyclerView
                            LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
                            outRange[0] = layoutManager.findFirstVisibleItemPosition();
                            outRange[1] = layoutManager.findLastVisibleItemPosition();
                        }

                        @Override
                        public void onDataRefresh() {
                            mRecyclerView.getAdapter().notifyDataSetChanged();
                        }

                        @Override
                        public void onItemLoaded(int position) {
                            mRecyclerView.getAdapter().notifyItemChanged(position);
                        }
                    });
            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    onRangeChanged();
                }
            });
        }
    }
}
FRL
sumber
1

@kushal @abdulaziz

Mengapa tidak menggunakan logika ini saja?

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    int totalItemCount, lastVisibleItemPosition;

    if (dy > 0) {
      totalItemCount = _layoutManager.getItemCount();
      lastVisibleItemPosition = _layoutManager.findLastVisibleItemPosition();

      if (!_isLastItem) {
        if ((totalItemCount - 1) == lastVisibleItemPosition) {
          LogUtil.e("end_of_list");

          _isLastItem = true;
        }
      }
    }
  }
leonapse
sumber
OnScroller saya () memanggil tiga kali untuk satu item jadi saya mendapatkan end_of_list tiga kali dan logika pagination saya disebut tiga kali. Bagaimana cara memperbaikinya dengan memanggil pagination hanya sekali.
ved
@ved Itu tidak seharusnya terjadi. Kode di atas memastikan end_of_listkondisi hanya akan dipanggil sekali. Bendera _isLastItemadalah variabel global dalam aktivitas yang memiliki nilai default false. Apa yang saya lakukan adalah menjalankan tugas latar belakang setelah mendeteksi akhir daftar, mengambil halaman berikutnya kemudian memberitahukan adaptor dataset baru, dan akhirnya menetapkan _isLastItemke false lagi.
leonapse
1

Coba di bawah ini:

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;

/**
 * Abstract Endless ScrollListener
 * 
 */
public abstract class EndlessScrollListener extends
        RecyclerView.OnScrollListener {
    // The minimum amount of items to have below your current scroll position
    // before loading more.
    private int visibleThreshold = 10;
    // The current offset index of data you have loaded
    private int currentPage = 1;
    // True if we are still waiting for the last set of data to load.
    private boolean loading = true;
    // The total number of items in the data set after the last load
    private int previousTotal = 0;
    private int firstVisibleItem;
    private int visibleItemCount;
    private int totalItemCount;
    private LayoutManager layoutManager;

    public EndlessScrollListener(LayoutManager layoutManager) {
        validateLayoutManager(layoutManager);
        this.layoutManager = layoutManager;
    }

    public EndlessScrollListener(int visibleThreshold,
            LayoutManager layoutManager, int startPage) {
        validateLayoutManager(layoutManager);
        this.visibleThreshold = visibleThreshold;
        this.layoutManager = layoutManager;
        this.currentPage = startPage;
    }

    private void validateLayoutManager(LayoutManager layoutManager)
            throws IllegalArgumentException {
        if (null == layoutManager
                || !(layoutManager instanceof GridLayoutManager)
                || !(layoutManager instanceof LinearLayoutManager)) {
            throw new IllegalArgumentException(
                    "LayoutManager must be of type GridLayoutManager or LinearLayoutManager.");
        }
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        visibleItemCount = recyclerView.getChildCount();
        totalItemCount = layoutManager.getItemCount();
        if (layoutManager instanceof GridLayoutManager) {
            firstVisibleItem = ((GridLayoutManager) layoutManager)
                    .findFirstVisibleItemPosition();
        } else if (layoutManager instanceof LinearLayoutManager) {
            firstVisibleItem = ((LinearLayoutManager) layoutManager)
                    .findFirstVisibleItemPosition();
        }
        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading
                && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            // End has been reached do something
            currentPage++;
            onLoadMore(currentPage);
            loading = true;
        }
    }

    // Defines the process for actually loading more data based on page
    public abstract void onLoadMore(int page);

}
shridutt kothari
sumber
1

Saya telah membuat LoadMoreRecyclerView menggunakan Abdulaziz Noor Answer

LoadMoreRecyclerView

public class LoadMoreRecyclerView extends RecyclerView  {

    private boolean loading = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;
    //WrapperLinearLayout is for handling crash in RecyclerView
    private WrapperLinearLayout mLayoutManager;
    private Context mContext;
    private OnLoadMoreListener onLoadMoreListener;

    public LoadMoreRecyclerView(Context context) {
        super(context);
        mContext = context;
        init();
    }

    public LoadMoreRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    public LoadMoreRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        init();
    }

    private void init(){
        mLayoutManager = new WrapperLinearLayout(mContext,LinearLayoutManager.VERTICAL,false);
        this.setLayoutManager(mLayoutManager);
        this.setItemAnimator(new DefaultItemAnimator());
        this.setHasFixedSize(true);
    }

    @Override
    public void onScrolled(int dx, int dy) {
        super.onScrolled(dx, dy);

        if(dy > 0) //check for scroll down
        {
            visibleItemCount = mLayoutManager.getChildCount();
            totalItemCount = mLayoutManager.getItemCount();
            pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

            if (loading)
            {
                if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount)
                {
                    loading = false;
                    Log.v("...", "Call Load More !");
                    if(onLoadMoreListener != null){
                        onLoadMoreListener.onLoadMore();
                    }
                    //Do pagination.. i.e. fetch new data
                }
            }
        }
    }

    @Override
    public void onScrollStateChanged(int state) {
        super.onScrollStateChanged(state);
    }

    public void onLoadMoreCompleted(){
        loading = true;
    }

    public void setMoreLoading(boolean moreLoading){
        loading = moreLoading;
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        this.onLoadMoreListener = onLoadMoreListener;
    }
}

WrapperLinearLayout

public class WrapperLinearLayout extends LinearLayoutManager
{
    public WrapperLinearLayout(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        try {
            super.onLayoutChildren(recycler, state);
        } catch (IndexOutOfBoundsException e) {
            Log.e("probe", "meet a IOOBE in RecyclerView");
        }
    }
}

// Tambahkan dalam xml like

<your.package.LoadMoreRecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</your.package.LoadMoreRecyclerView>

OnCreate atau onViewCreated

mLoadMoreRecyclerView = (LoadMoreRecyclerView) view.findViewById(R.id.recycler_view);
mLoadMoreRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                callYourService(StartIndex);
            }
        });

hubungi Layanan Anda

private void callYourService(){
    //callyour Service and get response in any List

    List<AnyModelClass> newDataFromServer = getDataFromServerService();
    //Enable Load More
    mLoadMoreRecyclerView.onLoadMoreCompleted();

    if(newDataFromServer != null && newDataFromServer.size() > 0){
            StartIndex += newDataFromServer.size();

            if (newDataFromServer.size() < Integer.valueOf(MAX_ROWS)) {
                    //StopLoading..
                   mLoadMoreRecyclerView.setMoreLoading(false);
            }
    }
    else{
            mLoadMoreRecyclerView.setMoreLoading(false);
            mAdapter.notifyDataSetChanged();
    }
}
Zar E Ahmer
sumber
1

Dimungkinkan juga untuk mengimplementasikan tanpa scroll listener, menggunakan logika murni dari model data saja. Tampilan gulir mengharuskan untuk mendapatkan item berdasarkan posisi serta jumlah item maksimal. Model dapat memiliki logika latar belakang untuk mengambil item yang diperlukan dalam potongan, bukan satu per satu, dan melakukan ini di utas latar belakang, memberi tahu tampilan ketika data siap.

Pendekatan ini memungkinkan untuk memiliki antrian pengambilan yang lebih memilih item yang paling baru-baru ini diminta (sehingga saat ini terlihat) daripada pengiriman yang lebih lama (kemungkinan besar sudah digulirkan), mengontrol jumlah utas paralel untuk digunakan dan hal-hal sejenisnya. Kode sumber lengkap untuk pendekatan ini (aplikasi demo dan pustaka yang dapat digunakan kembali) tersedia di sini .

Audrius Meskauskas
sumber
0

Ada metode public void setOnScrollListener (RecyclerView.OnScrollListener listener)di https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setOnScrollListener%28android.support.v7.widget.RecyclerView.OnScrollListener%29 . Gunakan itu

EDIT:

Ganti onScrollStateChangedmetode di dalam onScrollListenerdan lakukan ini

            boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;

            //loading is used to see if its already loading, you have to manually manipulate this boolean variable
            if (loadMore && !loading) {
                 //end of list reached
            }
Harimau kumbang
sumber
1
Harap lebih spesifik! Bagaimana cara menggunakan RecyclerView.OnScrollListener untuk menentukan bahwa pengguna menggulir ke bagian akhir daftar?
erdna
Tidak ada onScroll di RecyclerView.OnScrollListener ! Anda mencampur AbsListView.OnScrollListener dengan RecyclerView.OnScrollListener.
erdna
ya itu seharusnyaonScrollStateChanged
Panther
onScrollStateChangedtidak akan berfungsi karena hanya akan dipanggil ketika Anda mengubah status gulungan dan tidak saat Anda sedang menggulir.
Pedro Oliveira
@PedroOliveira Apakah mungkin dengan onScrollStateChangedmenentukan bahwa pengguna menggulir ke item terakhir?
erdna
0

Periksa ini setiap hal dijelaskan secara rinci: Pagination menggunakan RecyclerView Dari A ke Z

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView,
                                     int newState) {
        super.onScrollStateChanged(recyclerView, newState);
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        int visibleItemCount = mLayoutManager.getChildCount();
        int totalItemCount = mLayoutManager.getItemCount();
        int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();

        if (!mIsLoading && !mIsLastPage) {
            if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                    && firstVisibleItemPosition >= 0) {
                loadMoreItems();
            }
        }
    }
})

loadMoreItems ():

private void loadMoreItems() {
    mAdapter.removeLoading();
    //load data here from the server

    // in case of success
    mAdapter.addData(data);
    // if there might be more data
    mAdapter.addLoading();
}

di MyAdapter:

private boolean mIsLoadingFooterAdded = false;

public void addLoading() {
    if (!mIsLoadingFooterAdded) {
        mIsLoadingFooterAdded = true;
        mLineItemList.add(new LineItem());
        notifyItemInserted(mLineItemList.size() - 1);
    }
}

public void removeLoading() {
    if (mIsLoadingFooterAdded) {
        mIsLoadingFooterAdded = false;
        int position = mLineItemList.size() - 1;
        LineItem item = mLineItemList.get(position);

        if (item != null) {
            mLineItemList.remove(position);
            notifyItemRemoved(position);
        }
    }
}

public void addData(List<YourDataClass> data) {

    for (int i = 0; i < data.size(); i++) {
        YourDataClass yourDataObject = data.get(i);
        mLineItemList.add(new LineItem(yourDataObject));
        notifyItemInserted(mLineItemList.size() - 1);
    }
}
awsleiman
sumber
Tautan dapat berisi jawaban, tetapi cobalah untuk menjelaskan beberapa bagian substansial dari penjelasan dalam tautan di kiriman Anda.
Ian
0

Tidak satu pun dari jawaban ini yang memperhitungkan apakah daftar itu terlalu kecil atau tidak.

Berikut adalah sepotong kode yang telah saya gunakan yang berfungsi pada RecycleViews di kedua arah.

@Override
    public boolean onTouchEvent(MotionEvent motionEvent) {

        if (recyclerViewListener == null) {
            return super.onTouchEvent(motionEvent);
        }

        /**
         * If the list is too small to scroll.
         */
        if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
            if (!canScrollVertically(1)) {
                recyclerViewListener.reachedBottom();
            } else if (!canScrollVertically(-1)) {
                recyclerViewListener.reachedTop();
            }
        }

        return super.onTouchEvent(motionEvent);
    }

    public void setListener(RecyclerViewListener recycleViewListener) {
        this.recyclerViewListener = recycleViewListener;
        addOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                if (recyclerViewListener == null) {
                    return;
                }

                recyclerViewListener.scrolling(dy);

                if (!canScrollVertically(1)) {
                    recyclerViewListener.reachedBottom();
                } else if (!canScrollVertically(-1)) {
                    recyclerViewListener.reachedTop();
                }
            }

        });
    }
Oliver Dixon
sumber
0

Aku membiarkanmu aproximation ku. Bekerja dengan baik untuk saya.

Saya harap ini membantu Anda.

/**
 * Created by Daniel Pardo Ligorred on 03/03/2016.
 */
public abstract class BaseScrollListener extends RecyclerView.OnScrollListener {

    protected RecyclerView.LayoutManager layoutManager;

    public BaseScrollListener(RecyclerView.LayoutManager layoutManager) {

        this.layoutManager = layoutManager;

        this.init();
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

        super.onScrolled(recyclerView, dx, dy);

        this.onScroll(recyclerView, this.getFirstVisibleItem(), this.layoutManager.getChildCount(), this.layoutManager.getItemCount(), dx, dy);
    }

    private int getFirstVisibleItem(){

        if(this.layoutManager instanceof LinearLayoutManager){

            return ((LinearLayoutManager) this.layoutManager).findFirstVisibleItemPosition();
        } else if (this.layoutManager instanceof StaggeredGridLayoutManager){

            int[] spanPositions = null; //Should be null -> StaggeredGridLayoutManager.findFirstVisibleItemPositions makes the work.

            try{

                return ((StaggeredGridLayoutManager) this.layoutManager).findFirstVisibleItemPositions(spanPositions)[0];
            }catch (Exception ex){

                // Do stuff...
            }
        }

        return 0;
    }

    public abstract void init();

    protected abstract void onScroll(RecyclerView recyclerView, int firstVisibleItem, int visibleItemCount, int totalItemCount, int dx, int dy);

}
Dani
sumber
0

Solusi ini sangat cocok untuk saya.

//Listener    

public abstract class InfiniteScrollListener     extendsRecyclerView.OnScrollListener {

public static String TAG = InfiniteScrollListener.class.getSimpleName();
int firstVisibleItem, visibleItemCount, totalItemCount;
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 1;
private int current_page = 1;

private LinearLayoutManager mLinearLayoutManager;

public InfiniteScrollListener(LinearLayoutManager linearLayoutManager) {
    this.mLinearLayoutManager = linearLayoutManager;
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);

    visibleItemCount = recyclerView.getChildCount();
    totalItemCount = mLinearLayoutManager.getItemCount();
    firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

    if (loading) {
        if (totalItemCount > previousTotal) {
            loading = false;
            previousTotal = totalItemCount;
        }
    }
    if (!loading && (totalItemCount - visibleItemCount - firstVisibleItem <= visibleThreshold)) {

        current_page++;

        onLoadMore(current_page);

        loading = true;
    }
}

public void resetState() {
    loading = true;
    previousTotal = 0;
    current_page = 1;
}

public abstract void onLoadMore(int current_page);
}

//Implementation into fragment 
 private InfiniteScrollListener scrollListener;

scrollListener = new InfiniteScrollListener(manager) {
        @Override
        public void onLoadMore(int current_page) {
            //Load data
        }
    };
    rv.setLayoutManager(manager);
    rv.addOnScrollListener(scrollListener);
Giedrius Šlikas
sumber