RecyclerView के साथ अंतहीन सूची कैसे लागू करें?


346

मैं परिवर्तन करना चाहते हैं ListViewके लिए RecyclerView। मैं का उपयोग करना चाहते onScrollका OnScrollListenerमें RecyclerViewएक उपयोगकर्ता सूची के अंत में स्क्रॉल करता है, तो यह निर्धारित करने के।

मुझे कैसे पता चलेगा कि कोई उपयोगकर्ता सूची के अंत तक स्क्रॉल करता है ताकि मैं एक REST सेवा से नया डेटा प्राप्त कर सकूं?


कृपया इस लिंक की जाँच करें यह आपकी मदद करेगा .. stackoverflow.com/questions/26293461/…
samsad

32
कृपया प्रश्न को ध्यान से पढ़ें! मुझे पता है कि यह एक ListView के साथ कैसे करना है, लेकिन इसे रीसायकल व्यू के साथ कैसे लागू किया जाए, यह नहीं ।
इरना

android.data में loadmore onscrolllistener को कैसे कार्यान्वित किया जाए, लेकिन मौजूदा डेटा पर अपडेट किया गया है, कृपया मेरी मदद करें
हर्ष

2
आप इस लाइब्रेरी का उपयोग कर सकते हैं: github.com/rockerhieu/rv-adapter-endless । यह करने के विचार पर आधारित है cwac-endlessके लिए ListView
हियर रॉकर

जवाबों:


422

@ कुशाल को धन्यवाद और मैंने इसे कैसे लागू किया

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

जोड़ना मत भूलना

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

11
मैं क्या कर सकता हूंStaggeredGridLayoutManager
प्रतीक बुटानी

16
के बारे में क्याmLayoutManager.findLastCompletelyVisibleItemPosition()==mLayoutManager.getItemCount()-1
laaptu

45
सब जो करने के लिए findFirstVisibleItemPosition()हल नहीं किया आप बदलना चाहिए RecyclerView.LayoutManagerकरने के लिएLinearLayoutManager
अम्र मोहम्मद

26
loading = trueफिर से बनाने की शर्त कहाँ है ?
भार्गव

10
भाग के loading = trueबाद जोड़ना मत भूलना //Do pagination। अन्यथा यह कोड केवल एक बार चलेगा और आप अधिक आइटम लोड नहीं कर सकते।
शैशव जोगानी

165

ये चर बनाओ।

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

पुनर्नवीनीकरण दृश्य के लिए स्क्रॉल पर सेट करें।

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

नोट: सुनिश्चित करें कि आप के LinearLayoutManagerलिए लेआउट प्रबंधक के रूप में उपयोग कर रहे हैंRecyclerView

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

और एक ग्रिड के लिए

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

अपने अंतहीन स्क्रॉल के साथ मज़े करो !! ^। ^

अपडेट: mRecyclerView setOnScrollListener () को हटा दिया गया है और बस mRecyclerView.addOnScrollListener()चेतावनी के साथ बदल दिया जाएगा! आप इस SO प्रश्न से अधिक पढ़ सकते हैं

चूंकि एंड्रॉइड अब आधिकारिक रूप से कोटलिन का समर्थन करता है, यहां उसी के लिए एक अपडेट है -

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

और इसे इस तरह अपने RecyclerView में जोड़ें

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

एक पूर्ण कोड उदाहरण के लिए, इस Github रेपो को संदर्भित करने के लिए स्वतंत्र महसूस करें ।


14
कैसे GridLayoutManager के साथ इस समाधान को लागू करने का कोई विचार? चूंकि findFirstVisibleItemPosition()विधि केवल LinearLayoutManager के पास उपलब्ध है, इसलिए मैं यह पता नहीं लगा सकता कि इसे कैसे काम किया जाए।
मथिउमैरी

1
अतिरिक्त जानकारी: इस मामले में, उपयोग visibleItemCount = mLayoutManager.getChildCount();करने के समान व्यवहार करता है visibleItemCount = mRecyclerView.getChildCount();
जिंग ली

3
कोड को onScrolled () पद्धति के बजाय onScrollStateChanged () विधि में रखें।
अनिरुद्ध

2
@ toobsco42 आप इसका उपयोग कर सकते हैं:int[] firstVisibleItemPositions = new int[yourNumberOfColumns]; pastVisiblesItems = layoutManager.findFirstVisibleItemPositions(firstVisibleItemPositions)[0];
MathieuMaree

1
यह क्या है। विचाराधीन अदृश्यपरिवर्तन () नहीं सुलझा
सुरेश शर्मा

72

उन लोगों के लिए जो केवल अंतिम आइटम पूरी तरह से दिखाए जाने पर सूचित करना चाहते हैं, आप उपयोग कर सकते हैं View.canScrollVertically()

यहाँ मेरा कार्यान्वयन है:

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

नोट: recyclerView.getLayoutManager().canScrollVertically()यदि आप API <14 का समर्थन करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं ।


यह एक महान और सरल उत्तर है! धन्यवाद!
एंड्रानिक

2
इसी तरह के समाधान का उपयोग चेक द्वारा रीफ्रेश करने के लिए पुल के लिए किया जा सकता है! RecyclerView.canScrollVertically (-1)।
लॉर्डपर्सले

सबसे अच्छा समाधान वहाँ। धन्यवाद दोस्त!
अंगार

1
@LordParsley धन्यवाद, अपडेट किया गया। यह भी एक तरह से SwipeRefreshLayout है जिसे ताज़ा करने के लिए पुल की जाँच की जाती है।
हाई झांग 3

1
@EpicPandaForce यदि आप उपयोग कर रहे हैं, तो आप RecyclerViewफिर से भाग्यशाली होंगे, क्योंकि आप बस एक स्थिर प्रतिलिपि बना सकते हैं क्योंकि View.canScrollVertically()संबंधित विधियों को संरक्षित करने के बजाय सार्वजनिक चिह्नित किया गया है RecyclerView। आप चाहें तो RecyclerViewफिर से लागू करने के लिए विस्तार भी कर सकते canScrollVertically()हैं। एक तीसरा और सरल तरीका है कॉल करना recyclerView.getLayoutManager().canScrollVertically()। मेरे उत्तर में संपादित।
हाई झांग

67

यहाँ एक और दृष्टिकोण है। यह किसी भी लेआउट प्रबंधक के साथ काम करेगा।

  1. एडॉप्टर क्लास को अमूर्त बनाएं
  2. फिर अडैप्टर क्लास में एक अमूर्त विधि बनाएं (जैसे। लोड ())
  3. में onBindViewHolder स्थिति की जांच करता है, तो पिछले और कॉल लोड ()
  4. अपनी गतिविधि या टुकड़े में एडेप्टर ऑब्जेक्ट बनाते समय लोड () फ़ंक्शन को ओवरराइड करें।
  5. अधिक भार वाले फ़ंक्शन में अपने लोडमोर कॉल को लागू करें

विस्तार से समझने के लिए मैंने एक ब्लॉग पोस्ट लिखी और उदाहरण परियोजना इसे यहाँ प्राप्त करें 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
समाधान की तरह, आपको अपना एडॉप्टर अमूर्त बनाने की आवश्यकता नहीं है, इसके बजाय आप अपने एडेप्टर में एक इंटरफ़ेस बना सकते हैं और अपनी गतिविधि को इसे लचीला और सुरुचिपूर्ण रखते हुए कार्यान्वित कर सकते हैं, उदा: ItemDisplayListener => onItemDisplayed (int स्थिति)। इस तरह से आप किसी भी स्थिति में लोड कर सकते हैं: एन, एन -1, एन -2 पर ..
समीर

1
@ नमस्कार एक बूलियन समाप्त = गलत जोड़ें; जब आप अंतिम छोर तक पहुँचते हैं = सच्चा हो जाता है .. अगर ((स्थिति> = getItemCount) (- 1) && ((समाप्त))
सबीर मोहम्मद

1
इसे सही उत्तर के रूप में चिह्नित किया जाना चाहिए। यह सुरुचिपूर्ण और सरल है।
ग्रेग एननिस

2
पहले समाधान की लोकप्रियता के तहत दफन बेहतर समाधान का एक अच्छा उदाहरण है। बहुत बार, अंतिम पंक्ति एक अलग दृष्टिकोण के लिए बाध्य होगी जो "लोड हो रहा है ..." बैनर के रूप में कार्य करता है। जब इस दृश्य को बाइंड कॉल मिलती है, तो यह एक कॉलबैक स्थापित करेगा जो अधिक डेटा उपलब्ध होने पर डेटा परिवर्तन सूचना को ट्रिगर करता है। स्क्रॉल श्रोता को हुक करने का स्वीकृत उत्तर बेकार है, और शायद अन्य लेआउट प्रकारों के लिए काम नहीं करता है।
माइकल ने

3
यदि उपयोगकर्ता सक्रिय रूप से दूर और अंतिम आइटम पर वापस स्क्रॉल करता है तो @ केवल इसे पूरी तरह से कॉल कर सकता है। onBindViewHolder केवल तभी एक बार कॉल किया जाता है, जब प्रत्येक बार दृश्य स्क्रीन पर प्रवेश करता है और इसे लगातार कॉल नहीं करेगा।
डेविड लियू

18

मेरा जवाब नूर का एक संशोधित संस्करण है। मैं वहाँ से गुजरा ListViewजहाँ मेरे पास था EndlessScrollListener(ताकि आप एसओ पर कई उत्तरों में आसानी से पा RecyclerViewसकें ) तो मैं चाहता था कि एEndlessRecyclScrollListener आसानी से अपने पिछले श्रोता को अपडेट कर सकूं।

तो यहाँ कोड है, आशा है कि यह मदद करता है:

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
आपके कार्यान्वयन के लिए LinearLeayoutManager का उपयोग करने के लिए RecyclerView की आवश्यकता होती है। बुरा विचार!
ओरी

@ श्री आपको समझा सकते हैं कि क्यों? धन्यवाद!
फेडरिको पोंजी

1
अपने onScrolled में आपने RecyclerView से LinearLayoutManager तक LayoutManager को कास्ट किया। इसके StaggredGridLayout या किसी अन्य चीज़ के लिए काम नहीं कर रहा है। StaggredGridLayout में FFirstVoiceItemPosition () नहीं है।
ओरी जूल

@Orri कि बाहर इशारा करने के लिए धन्यवाद! लेकिन मुझे नहीं लगता कि यह इतना बुरा विचार है, क्योंकि यह मेरे और, अपवोट्स, अन्य मामलों के आधार पर काम करता है :)
फेडेरिको पोंजी

10

मेरे लिए, यह बहुत आसान है:

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

अतुल्यकालिक नौकरियों से सावधान रहें: अतुल्यकालिक नौकरियों के अंत में mLading को बदलना होगा। आशा है कि यह मददगार होगा!


मुझे मूल रूप से खुद से पूछताछ करने के दिनों के बाद यह जवाब मिला। यह सबसे अच्छा उपाय है, imo।
15 अक्टूबर को wsgeorge

लोडमोरम पेज नंबर पासिंग एंड्रॉइड
हर्षा

getWebServiceData (); mStoresAdapterData.setOnLoadMoreListener (new StoresAdapter.OnLoadMoreListener () {@Override public void onLoadMore () {// null जोड़ें, इसलिए अडैप्टर view_type की जाँच करेगा और नीचे की दुकानों पर प्रगति बार दिखाएगा ।List.add (null); () - 1); ++ पेजनंबर; गेटवेबसर्विडेटा ();}}}; दोनों एक दूसरे को अंततः 2 पेज डेटा के बाद एक ही बुला रहे हैं कृपया मदद करें
हर्ष

मैंने recyclerView
पेजेशन

9

अधिकांश उत्तर का RecyclerViewउपयोग करते हुए मान रहे हैं कि LinearLayoutManager, या GridLayoutManager, या यहां तक ​​कि StaggeredGridLayoutManager, या यह मानते हुए कि स्क्रॉल लंबवत या horyzontal है, लेकिन किसी ने भी पूरी तरह से सामान्य उत्तर पोस्ट नहीं किया है

ViewHolderएस एडाप्टर का उपयोग करना स्पष्ट रूप से एक अच्छा समाधान नहीं है। एक एडेप्टर में 1 से अधिक RecyclerViewइसका उपयोग हो सकता है । यह उनकी सामग्री को "स्वीकार" करता है। यह रिसाइक्लर व्यू होना चाहिए (जो कि वह वर्ग है जो उपयोगकर्ता के लिए वर्तमान में प्रदर्शित किए गए कार्यों के लिए जिम्मेदार है, न कि एडॉप्टर जो केवल सामग्री प्रदान करने के लिए जिम्मेदार है RecyclerView) जिसे आपके सिस्टम को सूचित करना चाहिए कि और आइटम की आवश्यकता है ( भार)।

यहाँ मेरा समाधान है, RecyclerView (RecycerView.LayoutManager और RecycerView.Adcape) के अमूर्त वर्गों के अलावा और कुछ नहीं:

/**
 * 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
आपका उत्तर सही है और यह LayoutManagersकेवल एक ही क्षण के लिए काम किया है : अपने गणना कोड को किसी अन्य स्क्रॉललिस्टर विधि में स्थानांतरित करें - onScrollStateChangedइसके बजाय इसे स्थानांतरित करें onScrolled। और onScrollStateChangedसिर्फ चेक में:if(newState == RecyclerView.SCROLL_STATE_IDLE) { // calculation code }
ट्रान्सर

आपकी सलाह के लिए धन्यवाद, लेकिन मुझे नहीं लगता कि यह एक बेहतर समाधान होगा। डेवलपर चाहता है कि उसके श्रोता को स्क्रॉल करने से पहले ही रिसाइकलव्यू बंद हो जाए। इसलिए यह नए डेटा आइटम (यदि डेटा को स्थानीय रूप से संग्रहीत किया जाता है) को लोड करने के लिए समाप्त हो सकता है, या यहां तक ​​कि रिसाइक्लेव्यू के अंत में एक प्रगति-बार दृश्य-धारक को जोड़ सकता है, इसलिए जब रिसाइक्लर्विस स्क्रॉल करने के लिए बंद हो जाएगा, तो यह एक सर्कल प्रगति पर हो सकता है अंतिम दृश्य के रूप में बार।
यारोप्रो

6

यद्यपि स्वीकृत उत्तर पूरी तरह से काम करता है, नीचे दिए गए समाधान addOnScrollListener का उपयोग करता है क्योंकि setOnScrollListener को पदावनत किया जाता है, और चर की संख्या कम कर देता है, और यदि स्थितियां।

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
कभी-कभी मेरे लोडमोर () विधि को तीन बार ऑनस्क्रोल्ड () कहा जाता है, किसी भी विचार को क्यों इसे तीन बार कहा जाता है और इसे कई बार कॉल करना बंद करना है।
वेद

डाई> 0 हमेशा गलत है
दुष्यंत सुथार

@ ऐसा इसलिए है क्योंकि स्क्रॉलिंग में 3 स्थितियाँ हैं: स्क्रॉल करना, स्क्रॉल करना, निष्क्रिय करना। आप एक उपयुक्त चुनें।
TheRealChx101

5

यद्यपि प्रश्न के बहुत सारे उत्तर हैं, मैं अंतहीन सूची दृश्य बनाने के अपने अनुभव को साझा करना चाहूंगा। हमने हाल ही में कस्टम कैरोसेल लेआउटमैनगर को लागू किया है जो कि सूची को असीम रूप से और साथ ही एक निश्चित बिंदु तक स्क्रॉल करके चक्र में काम कर सकता है। यहाँ GitHub पर एक विस्तृत विवरण दिया गया है

मेरा सुझाव है कि आप कस्टम लेआउट प्रबंधक बनाने पर छोटी लेकिन मूल्यवान सिफारिशों के साथ इस लेख पर एक नज़र डालें: http://cases.azoft.com/create-custom-layoutmanager-android/


5

कोटलिन के विस्तार कार्यों की शक्ति के साथ, कोड बहुत अधिक सुरुचिपूर्ण दिख सकता है। इसे आप कहीं भी रख दें (मेरे पास यह 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
                }
            }
        }
    })
}

और फिर इसे इस तरह उपयोग करें:

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

यह समाधान कुशाल शर्मा के उत्तर पर आधारित है। हालाँकि, यह थोड़ा बेहतर है क्योंकि:

  1. इसके onScrollStateChangedबजाय इसका उपयोग करता है onScroll। यह बेहतर है क्योंकि onScrollहर बार कहा जाता है कि RecyclerView में किसी भी तरह की हलचल होती onScrollStateChangedहै , जबकि केवल तब ही कॉल किया जाता है जब RecyclerView की स्थिति बदल जाती है। उपयोग करने onScrollStateChangedसे आपको सीपीयू समय की बचत होगी और, परिणामस्वरूप, बैटरी।
  2. चूंकि यह एक्सटेंशन फ़ंक्शंस का उपयोग करता है, इसका उपयोग आपके पास किसी भी RecyclerView में किया जा सकता है। क्लाइंट कोड सिर्फ 1 लाइन है।

जब मैंने SwipeRefreshLayout's setOnRefreshListener the addOnScrolledToEnd is not working निजी आंतरिक वर्ग खींच लिया PullToRefresh: SwipeRefreshLayout.OnRefreshListener {ओवरराइड मज़ा onRefresh () {pbViewMore !!। .isRefreshing = false}}
नवीन कुमार M

5

यह है कि मैं यह कैसे करते हैं, सरल और संक्षिप्त:

    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

ठीक है, मैंने इसे RecyclerView.Adcape की ऑनबाइंडहोल्डर विधि का उपयोग करके किया ।

एडाप्टर:

public interface OnViewHolderListener {
    void onRequestedLastItem();
}

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

    ...

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

विखंडन (या गतिविधि) :

@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 पर भरोसा करना बहुत अच्छा विचार नहीं है। RecyclerView कैश दृश्य करता है + कुछ लेआउट प्रबंधकों के पास पूर्व-कैश चीजों के लिए साधन हैं। मेरा सुझाव है कि एक स्क्रॉल श्रोता स्थापित करना और जब स्क्रॉल श्रोता बंद हो जाता है, लेआउट प्रबंधक से अंतिम दृश्य आइटम स्थिति प्राप्त करें। यदि आप डिफ़ॉल्ट लेआउट प्रबंधकों का उपयोग कर रहे हैं, तो उन सभी के पासLastV अदृश्य ** तरीके हैं।
यिगित

@yigit कितनी दूर RecyclerView चीजों को प्रिच करने की कोशिश करेगा? यदि आपके पास 500 आइटम हैं, तो मुझे वास्तव में संदेह है कि यह अब तक कैश होगा (अन्यथा यह प्रदर्शन का एक विशाल अपशिष्ट होगा)। जब यह वास्तव में कैश करना शुरू कर देगा (तब भी जब हम 480 तत्व पर होते हैं) इसका मतलब है कि यह वैसे भी एक और बैच लोड करने का समय है।
एलेक्स ओर्लोव

1
जब तक यह दूर की स्थिति में सहज स्क्रॉल न हो जाए, तब तक यह पूर्व की चीजों को नहीं बताता है। उस स्थिति में, एलएलएम (डिफ़ॉल्ट रूप से) एक के बजाय दो पृष्ठों को लेआउट करता है ताकि यह लक्ष्य दृश्य को खोज सके और इसे डीटेलरेट कर सके। यह कैश दृश्य करता है जो सीमा से बाहर जाते हैं। डिफ़ॉल्ट रूप से, यह कैश आकार 2 है और इसे setItemCacheSize के माध्यम से कॉन्फ़िगर किया जा सकता है।
यिगित

1
@ मैं सिर्फ समस्या के माध्यम से सोच रहा हूं कि मैं नहीं देखता कि कैशिंग यहां एक मुद्दा कैसे पेश कर सकता है; हम केवल पहली बार "अंतिम" आइटम में रुचि रखते हैं, वैसे भी बाध्य हैं! OnBindViewHolder पर कॉल मिस करना जब लेआउट मैनेजर पहले से बंधे हुए कैश्ड व्यू का फिर से उपयोग करता है तो यह केवल एक समस्या नहीं है जब हम सूची के अंत में अधिक डेटा पेजिंग में दिलचस्प होते हैं। सही बात?
ग्रेग एननिस

2
मेरे FlexibleAdapter लाइब्रेरी में मैंने कॉल के साथ अंतहीन स्क्रॉल को अपनाने के लिए चुना onBindViewHolder(), यह एक आकर्षण की तरह काम करता है। स्क्रॉल श्रोता की तुलना में कार्यान्वयन छोटा है और इसका उपयोग करना आसान है।
डेविड

3

लोडिंग इवेंट का पता लगाने का मेरा तरीका स्क्रॉलिंग का पता लगाना नहीं है, बल्कि यह सुनना है कि अंतिम दृश्य संलग्न था या नहीं। यदि अंतिम दृश्य संलग्न था, तो मैं इसे अधिक सामग्री लोड करने के लिए समय के रूप में मानता हूं।

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

मैं प्रयुक्त LayoutManager(जैसे LinearLayoutManager) और ओवरराइड scrollVerticallyBy()विधि का विस्तार करने की कोशिश करूंगा । सबसे पहले, मैं superपहले फोन करूंगा और फिर लौटाया गया पूर्णांक मान चेक करूंगा । यदि मान बराबर है 0तो नीचे या शीर्ष सीमा तक पहुँच जाता है। तब मैं उपयोग करूंगाfindLastVisibleItemPosition() पता लगाने के विधि का कि कौन सी सीमा तक पहुंच गया है और यदि आवश्यक हो तो अधिक डेटा लोड करें। एक विचार है।

इसके अलावा, आप ओवरस्क्रॉल की अनुमति देने और "लोडिंग" संकेतक दिखाने के लिए उस विधि से अपना मूल्य भी वापस कर सकते हैं।


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()काम नहीं करेगा क्योंकि यह केवल तब ही कहा जाएगा जब आप स्क्रॉल की स्थिति को बदलेंगे और जब आप स्क्रॉल कर रहे हों तब नहीं। आपको onScrolled()विधि का उपयोग करना चाहिए ।
mradzinski

2

मैंने onBindViewHolderअपनी RecyclerView.Adapterकक्षा की पद्धति में इस तर्क का उपयोग करते हुए एक अनंत स्क्रॉलिंग प्रकार का कार्यान्वयन प्राप्त किया ।

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

इस कोड के साथ जब RecyclerView अंतिम आइटम पर जाता है, तो यह वर्तमान पृष्ठ को बढ़ाता है और एक इंटरफेस पर कॉलबैक करता है जो एपी से अधिक डेटा लोड करने और एडॉप्टर में नए परिणाम जोड़ने के लिए जिम्मेदार है।

अगर यह स्पष्ट नहीं है तो मैं और अधिक पूर्ण उदाहरण पोस्ट कर सकता हूं?


मुझे पता है कि यह पोस्ट वास्तव में पुरानी है, लेकिन मैं कुछ हद तक नया हूँ और यह नहीं जानता कि आपके द्वारा तुलना किए जा रहे चरों को कहाँ से लाया जाए। mCurrentPage और mTotalPageCount आपके डेटा सेट को मान रहा है जो मैं मान रहा हूं, और mItems सूची आइटम की सरणी सूची है, लेकिन मैं स्थिति कैसे खोजूं?
बूलियनचेईस

आप देख सकते हैं कि मैंने अपना RecyclerView.Adapter को यहां कैसे लागू किया: github.com/dominicthomas/FlikrGridRecyclerView/blob/master/app/…
speedynomads

2

जो लोग यहां StaggeredGridLayoutManager का उपयोग करते हैं , उनके लिए मेरा कार्यान्वयन है, यह मेरे लिए काम करता है।

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

@ सुशीशमोहन यहां फुल क्लास है, यह छोटा है) मेरी परियोजना में मैं गतिशील रूप से स्पैन काउंट बदलता हूं, और यह 1 और 2 स्पैन काउंट के लिए काम करेगा
डेनिस ज़िन्कोवस्की

recyclerView.canScrollVertically (1) कर देगा, लेकिन इसके लिए API 14. की आवश्यकता है :(
सुधेश मोहन

2

इस नामित के लिए पुस्तकालय का उपयोग करने के लिए एक आसान है पृष्ठ पर अंक लगाना । ListView और RecyclerView (LinearLayout, GridLayout और StaggeredGridLayout) दोनों का समर्थन करता है।

यहाँ Github पर परियोजना का लिंक दिया गया है


2
  1. एक अमूर्त वर्ग बनाएँ और 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. गतिविधि में (या टुकड़ा) AddOnScrollListener को recyclerView में जोड़ें

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

1

मेरे पास एक विस्तृत उदाहरण है कि कैसे RecyclerView के साथ पेजेट करें। उच्च स्तर पर, मेरे पास एक सेट PAGE_SIZE है, जो 30 कहता है। इसलिए मैं 30 वस्तुओं का अनुरोध करता हूं और यदि मुझे 30 वापस मिलते हैं तो मैं अगले पृष्ठ का अनुरोध करता हूं। यदि मुझे 30 से कम आइटम मिलते हैं, तो मैं यह संकेत करने के लिए एक चर को चिह्नित करता हूं कि अंतिम पृष्ठ पहुंच गया है और फिर मैं अधिक पृष्ठों के लिए अनुरोध करना बंद कर देता हूं। इसे देखें और मुझे बताएं कि आप क्या सोचते हैं।

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


1

यहां वेब में AsyncListUtil का उपयोग करके मेरा समाधान कहता है: ध्यान दें कि यह वर्ग डेटा लोड करने के लिए एक एकल थ्रेड का उपयोग करता है, इसलिए यह माध्यमिक भंडारण जैसे डिस्क से डेटा लोड करने के लिए उपयुक्त है, लेकिन नेटवर्क से नहीं। लेकिन मैं डेटा को पढ़ने और ठीक काम करने के लिए odata का उपयोग कर रहा हूं। मुझे अपने उदाहरण डेटा एंटिटीज़ और नेटवर्क के तरीकों की याद आती है। मैं केवल उदाहरण एडाप्टर शामिल करता हूं।

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

@ कुशाल @abdulaziz

इसके बजाय इस तर्क का उपयोग क्यों नहीं करते?

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

मेरे onScroller () को एक ही आइटम के लिए तीन बार बुलाया जाता है, इसलिए मुझे तीन बार एंड_फ़ॉर्टलिस्ट और मेरे पेजेशन लॉजिक मिलते हैं। केवल एक बार ही पेजिंग को कॉल करने के लिए इसे कैसे ठीक करें।
ved

@ ऐसा होने वाला नहीं है। उपरोक्त कोड यह सुनिश्चित करता है कि end_of_listशर्त केवल एक बार बुलाई जाएगी। ध्वज _isLastItemगतिविधि में एक वैश्विक चर है जिसका डिफ़ॉल्ट मान है false। मैंने सूची के अंत का पता लगाने के बाद एक पृष्ठभूमि कार्य को निष्पादित करने के लिए क्या किया है, अगले पृष्ठ को फिर से प्राप्त करके नए डेटासेट के एडाप्टर को सूचित करें, और अंत में _isLastItemफिर से झूठे को सेट करें।
8

1

नीचे कोशिश करें:

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

मैंने अब्दुलअज़ीज़ नूर उत्तर का उपयोग करके LoadMoreRecyclerView बनाया है

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 में जोड़ें जैसे

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

OnCreate या 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

अकेले डेटा मॉडल के शुद्ध तर्क का उपयोग करके, स्क्रॉल श्रोता के बिना इसे लागू करना भी संभव है। स्क्रॉल दृश्य को आइटम द्वारा स्थिति के साथ-साथ अधिकतम आइटम गणना प्राप्त करने की आवश्यकता होती है। मॉडल में पृष्ठभूमि के तर्क हो सकते हैं कि आवश्यक वस्तुओं को एक-एक करके, बल्कि एक-एक करके, और डेटा तैयार होने पर दृश्य को सूचित करते हुए, पृष्ठभूमि में ऐसा करें।

इस दृष्टिकोण में अधिक से अधिक हाल ही में अनुरोध की गई (ताकि वर्तमान में दिखाई देने वाली) वस्तुएं (सबसे अधिक संभावना पहले से ही स्क्रॉल की गई) सबमिशन के लिए, जो कि उपयोग करने के लिए समानांतर थ्रेड्स की संख्या और चीजों को नियंत्रित करती हैं, को लाने की अनुमति है। इस दृष्टिकोण के लिए पूर्ण स्रोत कोड (डेमो ऐप और पुन: प्रयोज्य पुस्तकालय) यहां उपलब्ध हैं


0

इसमें एक विधि public void setOnScrollListener (RecyclerView.OnScrollListener listener)है https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setOnScrollListener%28android.support.v7.widget.RecyclerView.OnScrollListener%29 । उसका उपयोग करें

संपादित करें:

ओवरराइड onScrollStateChangedविधि को अंदर करें onScrollListenerऔर ऐसा करें

            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
कृपया और स्पष्ट बताएं! उपयोगकर्ता को सूची के अंत तक स्क्रॉल करने के लिए मैं RecyclerView.OnScrollListener का उपयोग कैसे करूं ?
इरना

RecyclerView.OnScrollListener पर कोई onScroll नहीं है ! आप RecLlerView.OnScrollListener के साथ AbsListView.OnScrollListener को मिलाएँ।
erdna

फिर यह माना जाता हैonScrollStateChanged
पैंथर

onScrollStateChangedकाम नहीं करेगा क्योंकि यह केवल तब ही कहा जाएगा जब आप स्क्रॉल की स्थिति को बदलेंगे और जब आप स्क्रॉल कर रहे हों तब नहीं।
पेद्रो ओलिवेरा

@PedroOliveira क्या यह onScrollStateChangedनिर्धारित करना संभव है कि उपयोगकर्ता अंतिम आइटम तक स्क्रॉल करता है?
erdna

0

इस बात की जाँच करें हर बात को विस्तार से बताया गया है: A से Z तक RecyclerView का उपयोग करके पृष्ठांकन

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

माय एडेप्टर में:

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

लिंक में एक उत्तर हो सकता है, लेकिन अपनी पोस्ट में लिंक में स्पष्टीकरण के कुछ पर्याप्त भागों को समझने का प्रयास करें।
इयान

0

यदि सूची बहुत छोटी है या नहीं, तो इनमें से कोई भी उत्तर ध्यान नहीं देता है।

यहाँ एक कोड है जिसका उपयोग मैं दोनों दिशाओं में RecycleViews पर काम कर रहा हूँ।

@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

मैंने तुम्हें अपनी औकात बता दी। मेरे लिए ठीक काम करता है।

मुझे उम्मीद है इससे आपको मदद मिली होगी।

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

यह समाधान मेरे लिए पूरी तरह से काम करता है।

//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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.