RecyclerView ile sonsuz liste nasıl uygulanır?


346

Ben değiştirmek istiyorum ListViewiçin RecyclerView. Ben kullanmak istiyorum onScrollait OnScrollListenerin RecyclerViewbir kullanıcı listesinin sonuna kaydırılan olmadığını belirlemek için.

Bir kullanıcının bir REST hizmetinden yeni veri alabilmem için listenin sonuna ilerleyip ilerlemediğini nasıl bilebilirim?


Lütfen bu bağlantıyı kontrol edin Size yardımcı olacaktır .. stackoverflow.com/questions/26293461/…
samsad

32
Lütfen soruyu dikkatlice okuyun! ListView ile bunu nasıl biliyorum ama nasıl bir RecycleView ile uygulamak için değil .
erdna

android.data loadmore onscrolllistener nasıl yüklenir ancak mevcut veriler üzerinde güncellenir lütfen bana yardım et
Harsha

2
Bu kütüphaneyi kullanabilirsiniz: github.com/rockerhieu/rv-adapter-endless . Bu fikrine dayanır cwac-endlessiçin ListView.
Hieu Rocker

Yanıtlar:


422

@Kushal sayesinde ve ben bunu böyle uyguladım

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

Eklemeyi unutma

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

11
Ne yapabilirimStaggeredGridLayoutManager
Pratik Butani

16
Peki yamLayoutManager.findLastCompletelyVisibleItemPosition()==mLayoutManager.getItemCount()-1
laaptu

45
Herkese findFirstVisibleItemPosition()değiştirmek gerekir çözülmezse RecyclerView.LayoutManageriçinLinearLayoutManager
Amr Mohammed

26
loading = truetekrar yapma koşulu nerede ?
Bhargav

10
Parçadan loading = truesonra eklemeyi unutmayın //Do pagination. aksi halde bu kod yalnızca bir kez çalışır ve daha fazla öğe yükleyemezsiniz.
Shaishav Jogani

165

Bu değişkenleri yapın.

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

Geri dönüşümcü görünümü için Kaydırma üzerine ayarlayın.

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

Not:LinearLayoutManager için mizanpaj yöneticisi olarak kullandığınızdan emin olun RecyclerView.

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

ve bir ızgara için

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

Sonsuz kaydırma ile eğlenin !! ^. ^

Güncelleme: mRecyclerView. setOnScrollListener () kullanımdan kaldırılmıştır, sadece ile değiştirin mRecyclerView.addOnScrollListener()ve uyarı kaybolacaktır! Bu SO sorusundan daha fazla okuyabilirsiniz .

Android artık Kotlin'i resmi olarak desteklediğinden, burada bir güncelleme var -

MakeScrollListener

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

ve RecyclerView'inize şöyle ekleyin

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

Tam kod örneği için bu Github deposuna başvurmaktan çekinmeyin .


14
Bu çözümü bir GridLayoutManager ile nasıl uygulayacağınız hakkında bir fikriniz var mı? Yana findFirstVisibleItemPosition()yöntem LinearLayoutManager ile yalnızca, işe nasıl anlamaya olamaz.
MathieuMaree

1
Ek bilgi: bu durumda, kullanma, kullanma visibleItemCount = mLayoutManager.getChildCount();ile aynı şekilde davranır visibleItemCount = mRecyclerView.getChildCount();.
Jing Li

3
Kodu onScrolled () yöntemi yerine onScrollStateChanged () yöntemine yerleştirin.
Anirudh

2
@ toobsco42 Bunu kullanabilirsiniz:int[] firstVisibleItemPositions = new int[yourNumberOfColumns]; pastVisiblesItems = layoutManager.findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
MathieuMaree

1
Nedir bu findFirstVisibleItemPosition () çözülmedi
Suresh Sharma

72

Yalnızca son öğe tamamen gösterildiğinde bildirim almak isteyenler için kullanabilirsiniz View.canScrollVertically().

İşte benim uygulama:

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

Not: recyclerView.getLayoutManager().canScrollVertically()API <14'ü desteklemek istiyorsanız kullanabilirsiniz.


Bu harika ve basit bir cevap! Teşekkür ederim!
Andranik

2
Benzer bir çözüm! RecyclerView.canScrollVertically (-1) 'i işaretleyerek yenileme yenilemesi için kullanılabilir.
LordParsley

Orada en iyi çözüm. Tesekkurler dostum!
Angmar

1
@LordParsley Teşekkür ederim, güncellendi. Bu aynı zamanda SwipeRefreshLayout'un çekmeyi yenilemek için kontrol etme yollarından biridir.
Hai Zhang

1
@EpicPandaForce kullanıyorsanız RecyclerView, tekrar şanslı olacaksınız, çünkü View.canScrollVertically()ilgili yöntemler korunmak yerine herkese açık olarak işaretlendiğinden , yalnızca statik bir kopyasını oluşturabilirsiniz RecyclerView. İsterseniz RecyclerViewyeniden uygulamayı da uzatabilirsiniz canScrollVertically(). Üçüncü ve basit bir yol aramaktır recyclerView.getLayoutManager().canScrollVertically(). Cevabımda düzenlendi.
Hai Zhang

67

İşte başka bir yaklaşım. Herhangi bir düzen yöneticisi ile çalışacaktır.

  1. Bağdaştırıcı sınıfını soyut yapma
  2. Sonra bağdaştırıcı sınıfında soyut bir yöntem oluşturun (örn. Load ())
  3. In onBindViewHolder konumunu kontrol eğer son ve çağrı yükü ()
  4. Etkinliğinizde veya parçanızda bağdaştırıcı nesnesi oluştururken load () işlevini geçersiz kılın.
  5. Overided load fonksiyonunda loadmore çağrınızı uygulayın

Ayrıntılı bir anlayış için bir blog yazısı yazdım ve örnek proje buraya getirin 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();
            }
        };
   }
}

3
Çözüm gibi, bağdaştırıcınızı soyut yapmak zorunda değilsiniz, bunun yerine bağdaştırıcınızda bir arabirim oluşturabilir ve etkinliğinizin esnek ve zarif kalmasını sağlayabilirsiniz, ör: ItemDisplayListener => onItemDisplayed (int pozisyon). Bu şekilde istediğiniz pozisyonda yükleyebilirsiniz: N, N-1, N-2 ..
Samer

1
@mcwise bir boole ekleyin bitmiş = false; Eğer ulaştığında uç yapmak doğrudur = bitmiş .. akımını değiştirirseniz durum için if ((pozisyon> = getItemCount () - 1) && (bitmiş)!)
Sabeer Mohammed

1
Bu doğru cevap olarak işaretlenmelidir. Bu zarif ve basit.
Greg Ennis

2
İlk çözümün popülaritesi altında gömülü üstün çözümün iyi bir örneği. Çok sık olarak, son satır "Yükleniyor ..." başlığı işlevi gören ayrı bir görüntüleme türüne bağlı olacaktır. Bu görünüm türü bir bağlama çağrısı aldığında, daha fazla veri olduğunda bir veri değişikliği bildirimini tetikleyen bir geri arama oluşturur. Kaydırma dinleyicisini bağlamanın kabul edilen cevabı boşa gider ve muhtemelen diğer düzen türleri için çalışmaz.
Michael Hays

3
@mcwise, yalnızca kullanıcı aktif olarak son öğeye geri dönerse geri durur. onBindViewHolder, görünüm ekrana her girdiğinde yalnızca bir kez çağrılır ve sürekli olarak çağrılmaz.
David Liu

18

Cevabım Noor'un değiştirilmiş bir versiyonudur. Ben ListViewvardı bir yerden EndlessScrollListener(SO üzerinde birçok cevap kolayca bulabilirsiniz) bir RecyclerViewöylesine bir EndlessRecyclScrollListenergeçmiş dinleyicimi kolayca güncellemek istedim .

İşte kod, umarım yardımcı olur:

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

}

1
Uygulamanız için LinearLeayoutManager'ı kullanmak için RecyclerView gerekir. Kötü bir fikir!
Orri

@Orri Lütfen nedenini açıklar mısınız? Teşekkürler!
Federico Ponzi

1
OnScrolled öğenizde LayoutManager'ı RecyclerView öğesinden LinearLayoutManager öğesine yayınladınız. StaggredGridLayout veya başka bir şey için çalışmıyor. StaggredGridLayout içinde findFirstVisibleItemPosition () yöntemi yoktur.
Orri

@Orri Bunu işaret ettiğiniz için teşekkürler! Ama bu kadar kötü bir fikir olduğunu düşünmüyorum, çünkü benim ve vekillere, diğer vakalara göre çalıştı :)
Federico Ponzi

10

Benim için çok basit:

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

Eşzamansız işlere dikkat edin: eşzamansız işlerin sonunda mLboading değiştirilmelidir. Umarım faydalı olacaktır!


Bu cevabı günlerce kendimi sorguladıktan sonra buldum. Bu en iyi çözüm, imo.
wsgeorge

yükleyen sayfa numarası android geçen ile geri dönüşüm için biraz çözüm verin
Harsha

getWebServiceData (); mStoresAdapterData.setOnLoadMoreListener (yeni StoresAdapter.OnLoadMoreListener () {@Override genel boşluğunu geçersiz kıl onLoadMore () {// null ekle; () - 1); ++ pageNumber; getWebServiceData ();}}); her ikisi de birbiri ardına nihayet 2. sayfa verisi sadece görsel görünmektedir yardım lütfen
Harsha

i recyclerView sayfalama birçok uygulama denedim ama hiçbiri çalıştı, bunun dışında benim benim oyum efendim var
Muhammed Elrashied

9

Çoğu cevap, RecyclerViewa LinearLayoutManager, veya GridLayoutManagerhatta StaggeredGridLayoutManager, hatta kaydırmanın dikey veya horyzontal olduğunu varsayar, ancak hiç kimse tamamen genel bir cevap göndermemiştir .

Kullanılması ViewHolderbireyin adaptörü açıkça iyi bir çözüm değildir. Bir bağdaştırıcıyı RecyclerViewkullanırken 1'den fazla olabilir . İçeriğini "uyarlar". Sisteminize daha fazla öğeye ihtiyaç duyulduğunu bildirmesi gereken ( yalnızca kullanıcıya içerik sağlamaktan sorumlu olan adaptör değil) Recycler View ( Geri Dönüşümci GörünümüRecyclerView ) olmalıdır . yük).

İşte benim RecyclerView (RecycerView.LayoutManager ve RecycerView.Adapter) soyutlanmış sınıfları dışında hiçbir şey kullanarak benim çözüm:

/**
 * 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.
    }
}

1
Cevabınız doğru ve LayoutManagerssadece bir an için işe yaradı : hesaplama kodunuzu başka bir scrollListener yönteminde taşıyın - bunun onScrollStateChangedyerine taşıyın onScrolled. Ve onScrollStateChangedkontrol edin:if(newState == RecyclerView.SCROLL_STATE_IDLE) { // calculation code }
Trancer

Tavsiyeniz için teşekkürler, ancak bunun daha iyi bir çözüm olacağını düşünmüyorum. Geliştirici, geri dönüşüm görünümü kaymayı bırakmadan önce dinleyicisinin tetiklenmesini istiyor. Bu nedenle, yeni veri öğelerinin yüklenmesi (veriler yerel olarak depolanıyorsa) veya hatta geri dönüşüm görünümünün sonuna bir ilerleme çubuğu görünüm tutucu eklenmesi tamamlanabilir; -en son görünür öğe olarak bar.
Yairopro

6

Kabul edilen cevap mükemmel bir şekilde çalışmasına rağmen, setOnScrollListener kullanımdan kaldırıldığı için aşağıdaki çözüm addOnScrollListener kullanır ve değişkenlerin sayısını ve koşullarını azaltır.

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

1
Bazen onScrolled () 'de thrice olarak adlandırılan loadMore () yöntemi, neden thrice olarak adlandırıldığı ve birden çok kez çağrılmasının nasıl durdurulacağı hakkında herhangi bir fikir.
ved

dy> 0 her zaman yanlıştır
Dushyant Suthar

@ved Çünkü kaydırmanın 3 durumu vardır: kaydırma, kaydırma, boşta. Uygun olanı seçersiniz.
TheRealChx101

5

Sorunun çok fazla yanıtı olmasına rağmen, sonsuz liste görünümü oluşturma deneyimimizi paylaşmak istiyorum. Kısa bir süre önce, listeyi sınırsız ve belirli bir noktaya kadar kaydırarak döngüde çalışabilen özel Carousel LayoutManager'ı uyguladık. İşte GitHub hakkında ayrıntılı açıklama .

Özel LayoutManagers oluşturmayla ilgili kısa ancak değerli önerilerle bu makaleye göz atmanızı öneririz: http://cases.azoft.com/create-custom-layoutmanager-android/


5

Kotlin'in uzatma işlevlerinin gücü ile kod çok daha zarif görünebilir. Bunu istediğiniz yere koyun (bir ExtensionFunctions.kt dosyasında var):

/**
 * 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
                }
            }
        }
    })
}

Ve sonra böyle kullanın:

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

Bu çözüm Kushal Sharma'nın cevabına dayanıyor. Ancak, bu biraz daha iyi çünkü:

  1. Bunun onScrollStateChangedyerine kullanır onScroll. Bu daha iyidir çünkü onScrollRecyclerView'de her tür hareket onScrollStateChangedolduğunda çağrılırken, sadece RecyclerView durumu değiştirildiğinde çağrılır. Kullanmak onScrollStateChangedCPU zamanından ve sonuç olarak pilden tasarruf etmenizi sağlayacaktır.
  2. Bu, Ek İşlevleri kullandığından, sahip olduğunuz herhangi bir RecyclerView öğesinde kullanılabilir. İstemci kodu sadece 1 satırdır.

Ne zaman ı did SwipeRefreshLayout's setOnRefreshListener the addOnScrolledToEnd is not working özel iç sınıf PullToRefresh: SwipeRefreshLayout.OnRefreshListener {eğlenceli onRefresh () {pbViewMore !!. Visibility = View.GONE pageCount = 0 courseList.clear () // çağırma burada srlNoMessageRefreshLayout !!. İsRefipe! ! .isRefreshing = false}}
Naveen Kumar M

5

Ben böyle, basit ve kısa:

    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

            }
        }
    });

3

Tamam, RecyclerView.Adapter onBindViewHolder yöntemini kullanarak yaptım .

Adaptör:

public interface OnViewHolderListener {
    void onRequestedLastItem();
}

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

    ...

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

Parça (veya Etkinlik) :

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

1
onBind'e güvenmek çok iyi bir fikir değil. RecyclerView önbellek görünümleri yapar + bazı düzen yöneticileri şeyler önbelleğe almak için araçlar vardır. Bir kaydırma dinleyicisi ayarlamanızı öneririm ve kaydırma dinleyicisi durduğunda, düzen yöneticisinden son görünür öğe konumunu alın. Varsayılan mizanpaj yöneticileri kullanıyorsanız, hepsinin findLastVisible ** yöntemleri vardır.
yigit

@yigit RecyclerView bir şeyleri ne kadar uzak tutmaya çalışır? 500 öğeniz varsa, şimdiye kadar önbelleğe alacağından şüpheliyim (aksi takdirde sadece dev bir performans kaybı olacaktır). Aslında önbelleklemeye başladığımızda (480 öğede bile olsa), başka bir toplu işi yüklemenin zamanı geldi demektir.
Alex Orlov

1
Uzaktaki bir konuma düzgün bir şekilde kaydırılmadığı sürece önbellekleri sümüklemez. Bu durumda, LLM (varsayılan olarak), hedef görünümü bulabilmesi ve yavaşlayabilmesi için biri yerine iki sayfa düzenler. Sınırların dışına çıkan önbellek görünümlerini yapar. Varsayılan olarak, bu önbellek boyutu 2'dir ve setItemCacheSize aracılığıyla yapılandırılabilir.
Yiğit

1
@yigit sadece problemi düşünerek önbelleğe almanın burada bir sorunu nasıl sunabileceğini görmüyorum; biz sadece ilk kez ilgilenen "son" öğeleri zaten bağlı! Düzen yöneticisi, önceden bağlanmış bir önbelleğe alınmış görünümü yeniden kullandığında onBindViewHolder çağrısını kaçırmak, listenin sonunda daha fazla veriyi sayfalamakla ilgilendiğimizde sorun olmaz. Doğru?
Greg Ennis

2
FlexibleAdapter kütüphanemde, çağrıyla sonsuz kaydırmayı benimsemeyi seçtim onBindViewHolder(), bir cazibe gibi çalışır. Uygulama, kaydırma dinleyicisine kıyasla küçüktür ve kullanımı daha kolaydır.
Davideas

3

Yükleme olayını tespit etme yöntemim, kaydırmayı algılamak değil, son görünümün eklenip eklenmediğini dinlemek. Son görünüm eklendiyse, daha fazla içerik yükleme zamanlaması olarak görüyorum.

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

2

Ben kullanılmış LayoutManager(örneğin LinearLayoutManager) uzatmak ve geçersiz kılma scrollVerticallyBy()yöntemi. Öncelikle, önce çağırır superve sonra döndürülen tamsayı değerini kontrol ederdim . Değer eşitse 0bir alt veya bir üst sınıra ulaşılır. Sonra findLastVisibleItemPosition()hangi sınıra ulaşıldığını bulmak ve gerekirse daha fazla veri yüklemek için yöntem kullanırdım . Sadece bir fikir.

Buna ek olarak, değerinizi bu yönteme göre fazla kaydırmaya ve "yükleme" göstergesini göstermeye bile döndürebilirsiniz.


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

1
onScrollStateChanged()çalışmaz, çünkü yalnızca kaydırma durumunu değiştirdiğinizde çağrılırsınız, siz kaydırma sırasında değil. onScrolled()Yöntemi kullanmalısınız .
mradzinski

2

Sınıfımın onBindViewHolderyönteminde bu mantığı kullanarak sonsuz bir kaydırma türü uygulaması gerçekleştirdim RecyclerView.Adapter.

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

RecyclerView son öğeye ulaştığında bu kodla, geçerli sayfa ve geri çağrıları, API'den daha fazla veri yüklemek ve bağdaştırıcıya yeni sonuçlar eklemekten sorumlu olan bir arabirimde artırır.

Bu net değilse daha eksiksiz bir örnek gönderebilir miyim?


Bu yazının gerçekten eski olduğunu biliyorum, ama biraz yeniyim ve karşılaştırdığınız değişkenleri nereden alacağınızı bilmiyorum. mCurrentPage ve mTotalPageCount sanırım veri kümenize atıfta bulunuyor ve mItems liste öğelerinin düzenleyicisidir, ancak konumu nasıl bulabilirim?
BooleanCheese

RecyclerView.Adapter'ımı nasıl uyguladığımı burada görebilirsiniz: github.com/dominicthomas/FlikrGridRecyclerView/blob/master/app/…
speedynomads

2

StaggeredGridLayoutManager'ı kullanan kişiler için benim uygulama burada, benim için çalışıyor.

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

@SudheeshMohan İşte tam sınıf, küçük) Projemde dinamik olarak span sayısını değiştiriyorum ve 1 ve 2 span sayısı için çalışacak
Dennis Zinkovski

recyclerView.canScrollVertically (1) bunu yapacak, ancak API 14 gerektiriyor. :(
Sudheesh Mohan

2

Bu adlandırılmış paginate için kullanımı kolay bir kütüphane var . ListView ve RecyclerView (LinearLayout, GridLayout ve StaggeredGridLayout) özelliklerini destekler.

İşte Github'daki projenin bağlantısı


2
  1. Soyut bir sınıf oluşturun ve RecyclerView.OnScrollListener'ı genişletir

    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. etkinlik (veya parça) içinde recyclerView öğesine addOnScrollListener ekleyin

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

1

RecyclerView ile sayfalandırma nasıl oldukça ayrıntılı bir örneği var. Yüksek düzeyde, bir dizi PAGE_SIZE var, diyelim 30 diyelim. Bu yüzden 30 ürün talep ediyorum ve 30 geri alırsam sonraki sayfayı talep ediyorum. 30'dan az öğe alırsam, bir değişkenin son sayfaya ulaşıldığını belirtmek için işaretlerim ve daha fazla sayfa istemeyi durdururum. Göz atın ve ne düşündüğünüzü bana bildirin.

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


1

Burada AsyncListUtil kullanarak benim çözüm , web diyor ki: Bu sınıf veri yüklemek için tek bir iş parçacığı kullanır, bu nedenle disk gibi ikincil depolama, ancak ağdan veri yüklemek için uygun olduğunu unutmayın. ama veri okumak ve iyi çalışmak için odata kullanıyorum. Örnek veri varlıklarımı ve ağ yöntemlerini özlüyorum. Yalnızca örnek adaptörü dahil ediyorum.

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

1

@kushal @abdulaziz

Bunun yerine neden bu mantığı kullanmıyorsunuz?

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

Benim onScroller () tek bir öğe için üç kez çağırdı, bu yüzden end_of_listesi üç kez ve sayfalama mantığım üç kez alıyorum. Sayfa numaralandırmayı yalnızca bir kez çağırmak için nasıl düzeltilir?
ved

@ved Bunun olması gerekmiyor. Yukarıdaki kod, end_of_listkoşulun yalnızca bir kez çağrılmasını sağlar. Bayrak _isLastItem, etkinlikte varsayılan değeri olan genel bir değişkendir false. Yaptığım şey, listenin sonunu algıladıktan sonra bir sonraki sayfayı alıp yeni veri kümesinin bağdaştırıcısına bildirmek ve son olarak _isLastItemtekrar false olarak ayarlamak için bir arka plan görevi yürütmektir .
leonapse

1

Aşağıdan deneyin:

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

}

1

Abdulaziz Noor Answer kullanarak LoadMoreRecyclerView oluşturdum

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

// xml gibi ekleyin

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

OnCreate veya onViewCreated

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

callYourService

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

1

Sadece veri modelinin saf mantığını kullanarak kaydırma dinleyici olmadan da uygulamak mümkündür. Kaydırma görünümünde, öğelerin konuma ve maksimum öğe sayısına göre alınması gerekir. Model, gerekli öğeleri tek tek değil, parçalar halinde almak için arka plan mantığına sahip olabilir ve bunu arka plan iş parçacığında yapabilir ve veriler hazır olduğunda görünümü bildirir.

Bu yaklaşım, en son istenen (şu anda görünür durumda olan) öğeleri daha eski (büyük olasılıkla zaten kaydırılmış) tercihlere tercih eden getirme kuyruğunun bulunmasına, kullanılacak paralel iş parçacıklarının sayısını ve benzerlerini kontrol etmesini sağlar. Bu yaklaşım için tam kaynak kodu (demo uygulaması ve yeniden kullanılabilir kütüphane) burada bulunabilir .


0

Https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setOnScrollListener%28android.support.v7.widget.RecyclerView.OnScrollListener%29'da bir yöntem public void setOnScrollListener (RecyclerView.OnScrollListener listener)vardır . Bunu kullan

DÜZENLE:

onScrollStateChangedİçindeki yöntemi geçersiz kıl onScrollListenerve bunu yap

            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
            }

1
Lütfen daha spesifik ol! Kullanıcının listenin sonuna geldiğini belirlemek için RecyclerView.OnScrollListener'ı nasıl kullanabilirim ?
erdna

RecyclerView.OnScrollListener'da onScroll yok ! AbsListView.OnScrollListener ile RecyclerView.OnScrollListener karıştırın.
erdna

ya olması gerekiyoronScrollStateChanged
Panther

onScrollStateChangedçalışmaz, çünkü yalnızca kaydırma durumunu değiştirdiğinizde çağrılırsınız, siz kaydırma sırasında değil.
Pedro Oliveira

@PedroOliveira Kullanıcının onScrollStateChangedson öğeye kaydırdığını belirlemek mümkün mü?
erdna

0

Bunu her şeyin ayrıntılı olarak açıklandığını kontrol edin: Recycler kullanarak sayfalandırma A'dan Z'ye

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

MyAdapter içinde:

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

Bağlantı bir yanıt içerebilir, ancak yayınınızdaki bağlantıdaki açıklamaların bazı önemli kısımlarını açıklamaya çalışın.
Ian

0

Liste çok küçükse veya değilse, bu cevapların hiçbiri dikkate alınmaz.

İşte RecycleViews üzerinde her iki yönde çalışan bir kod parçası.

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

        });
    }

0

Yaklaţtýrmamý istiyorum. Benim için iyi çalışıyor.

Umarım size yardımcı olur.

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

}

0

Bu çözüm benim için mükemmel çalışıyor.

//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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.