RecyclerView के नीचे स्क्रॉल कैसे करें? ScrollToPosition काम नहीं करता है


161

मैं गतिविधि को लोड करने के बाद RecyclerView सूची के नीचे स्क्रॉल करना चाहता हूं।

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...)RecyclerView में समर्थित नहीं होने के बारे में एक अपवाद फेंकता है, और conversationView.scrollToPosition(...)कुछ भी करने के लिए प्रतीत नहीं होता है।

कोड के उपरोक्त ब्लॉक के बाद, मैंने जोड़ा

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

जो काम नहीं करता है। में 30 तत्व हैं GENERIC_MESSAGE_LIST


क्या आप scrollToPositionएडॉप्टर सेट करने के तुरंत बाद कॉल कर रहे हैं ?
इयानहनिबेलके

@ianhanniballake हाँ, यह सही है conversationView.setAdapter(conversationViewAdapter);
वेलाविंडेंडर 5

4
यह शायद इसलिए है क्योंकि आप -1 के बजाय +1 को कॉल कर रहे हैं इसलिए 5 वें तत्व की स्थिति [4] होगी क्योंकि यह 0. पर शुरू होता है। +1 करने से आपको एक ArrayOutOfBounds मिलेगा ... क्या यह वहां क्रैश नहीं हुआ था?
RCB

1
सेटपैड एडाप्टर mRecyclerView.scrollToPosition (CarsList.size () - 1) के बाद जोड़ें;
वेबसर्विस

जवाबों:


194

बस सेट setStackFromEnd=trueया setReverseLayout=trueइतना है कि एलएलएम अंत से आइटम लेआउट करेगा।

इन दोनों के बीच का अंतर यह है कि setStackFromEndअंतिम तत्व को दिखाने के लिए दृश्य सेट किया जाएगा, लेआउट दिशा समान रहेगी। (इसलिए, बाएँ-से-दाएँ क्षैतिज पुनर्नवीनीकरण दृश्य में, अंतिम तत्व दिखाया जाएगा और बाईं ओर स्क्रॉल करने से पहले के तत्व दिखाई देंगे)

जबकि setReverseLayoutएडेप्टर द्वारा जोड़े गए तत्वों के क्रम को बदल देगा। लेआउट अंतिम तत्व से शुरू होगा, जो एलटीआर रिसाइक्लर व्यू में सबसे बाईं ओर होगा और फिर, दाईं ओर स्क्रॉल करने से पहले के तत्व दिखाई देंगे।

नमूना:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);

देखें प्रलेखन जानकारी के लिए।


132
यह कुछ उपयोगकर्ता हो सकता है, लेकिन यह उस प्रश्न का उत्तर नहीं देता है जो पूछा गया था।
जॉसफ

6
यदि आप दोनों stackFromEnd = true और setReverseLayout = सेट करते हैं तो यह सही नहीं है। क्या किसी को कोई वर्कअराउंड पता है?
लुकास कोरीया

10
चैट व्यू के लिए linearLayoutManager.setStackFromEnd (true) काम करता है।
मुनीब मिर्ज़ा

7
यह प्रश्न को बिल्कुल भी संबोधित नहीं करता है।
ऑर्बिट

1
केवल तब तक काम करता है जब तक कि दृश्य भरा न हो। यह स्क्रॉल का इरादा नहीं करता है, बस नीचे से स्टैक होता है।
मिग्युएलएसएलवी

376

मैं उत्तर खोजने के लिए इस पोस्ट को देख रहा था लेकिन ... मुझे लगता है कि इस पोस्ट पर हर कोई मेरे जैसे ही परिदृश्य का सामना कर रहा scrollToPosition()था : एक स्पष्ट कारण के लिए, पूरी तरह से नजरअंदाज कर दिया गया था।

मैं क्या उपयोग कर रहा था?

recyclerView.scrollToPosition(items.size());

... क्या काम किया ?

recyclerView.scrollToPosition(items.size() - 1);

6
recyclerView.scrollToPosition(messages.size()-1);वास्तव में मेरे लिए काम करता है, मैं सिर्फ आश्चर्यचकित हूं।
इंजन बाई

25
इसने मेरे लिए काम किया। यह वास्तव में समझ में आता है क्योंकि जावा सूची शून्य आधारित हैं। उदाहरण सूची [0,1,2] का आकार 3 है लेकिन अंतिम स्थिति 2 है क्योंकि यह 0. से शुरू होती है
केल्विन

19
FYI करें, एक चिकनी स्क्रॉल के लिए, वहाँ है smoothScrollToPosition(...)
इवान मोर्गिलो

5
@ इवान मॉर्गिलो smoothScrollToPosition बिल्कुल काम नहीं करता है: एस
cesards

2
@IvanMorgillo - आपका उत्तर परिणाम के साथ बेहतर काम करना चाहता है और अधिक चिकनी = डी। ऐसा लगता है कि स्क्रॉल टू पोज़िशन मेरे लिए थोड़ी छोटी है (मेरा अनुमान है कि फंक्शन नाम और देखने के निर्माण के बीच थोड़ी देरी है; वैसे भी यह ठीक से काम नहीं कर रहा है)
Roee

54

मैं इसका उत्तर देना देर से जानता हूं, फिर भी यदि कोई समाधान जानना चाहता है तो नीचे है

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);

8
यह होना चाहिए conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() **-1**);क्योंकि सूची में स्थितियां शून्य-आधारित हैं।
बेरोक डे

2
यह अभ्यस्त यदि अंतिम पंक्ति की ऊंचाई अधिक है तो स्क्रीन ऊंचाई है।
अनुज जिंदल

यह वही है जो मुझे चाहिए था। हालांकि मुझे सब कुछ सही ढंग से काम करने के लिए एक हैंडलर पोस्टडेल में लपेटना पड़ा।
मार्क अलेक्जेंडर

18

Recyclerview में नीचे की ओर किसी भी स्थिति से स्कोरलडाउन करने के लिए

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv.scrollToPosition(rv.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });

15

संदेश भेजने के बाद और सर्वर से संदेश प्राप्त करने से पहले इस कोड को जोड़ें

recyclerView.scrollToPosition(mChatList.size() - 1);

10

जब आप कॉल करते हैं setAdapter, तो वह तुरंत स्क्रीन पर स्थिति और स्थिति आइटम नहीं रखता है (जो एक एकल लेआउट पास लेता है) इसलिए आपके scrollToPosition()कॉल के पास स्क्रॉल करने के लिए कोई वास्तविक तत्व नहीं हैं।

इसके बजाय, आपको एक ViewTreeObserver.OnGlobalLayoutListener ( addOnGlobalLayoutListner ()ViewTreeObserver द्वारा निर्मित ) से पंजीकृत करना चाहिए conversationView.getViewTreeObserver()जो आपके scrollToPosition()पहले लेआउट पास होने के बाद देरी करता है :

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  public void onGlobalLayout() {
    conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
    // Unregister the listener to only call scrollToPosition once
    conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

    // Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as 
    // removeGlobalOnLayoutListener is deprecated.
    // They do the same thing, just a rename so your choice.
  }
});

1
धन्यवाद, लेकिन यह काम नहीं करता है। यह काम करने से रोकने से स्क्रॉलिंग को तोड़ता है, और यदि आप खींचते हैं, तो यह अजीब तरह से तेजी से स्क्रॉल करता है।
वेलाविंडेंडर

लगता है जैसे आप श्रोता को हटा नहीं रहे हैं। इसे केवल एक बार ठीक-ठीक एक बार बुलाया जाना चाहिए (तत्वों के ठीक पहले बाहर किए जाने के बाद) और स्क्रॉलिंग के दौरान बिल्कुल नहीं।
atहनुनीबल्लके

OnGlobalLayoutListenerशायद हटाया नहीं जा रहा है क्योंकि आप के लिए जाँच कर रहे हैं vto.isAlive()। मुझे इसका कारण नहीं पता है, लेकिन ViewTreeObserverकभी-कभी ए के लिए बदल दिया जाता है View, इसलिए isAliveआपके लिए बेहतर तरीके से जांच करने के बजाय बस इसके ViewTreeObserverसाथ चालू करेंconversationView.getViewTreeObserver().removeGlobalOnLayoutListener
दिमित्री ज़ैतसेव

@ianhanniballake मैंने इस मुद्दे को ठीक करने के लिए एक संपादन प्रस्तावित किया है।
साकेत

6

कोटलिन के लिए समाधान :

"recyclerView.adapter" या "recyclerView.adapter.notifyDataSetChanged ()" सेट करने के बाद कोड नीचे लागू करें

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)

5

कोटलिन में:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)

हाह, धन्यवाद GlobalLayoutListener! रिफैक्टरिंग के बाद मुझे स्क्रॉल करने के लिए आपके तरीके का उपयोग करना पड़ा। में तरह श्रोता को दूर करने के लिए मत भूलना stackoverflow.com/questions/28264139/... , या आप शुरू करने से RecyclerView वापस स्क्रॉल नहीं होंगे।
कूलमाइंड

4
class MyLayoutManager extends LinearLayoutManager {

  public MyLayoutManager(Context context) {
    super(context, LinearLayoutManager.VERTICAL, false);
  }

  @Override public void smoothScrollToPosition(RecyclerView recyclerView,
      final RecyclerView.State state, final int position) {

    int fcvip = findFirstCompletelyVisibleItemPosition();
    int lcvip = findLastCompletelyVisibleItemPosition();

    if (position < fcvip || lcvip < position) {
      // scrolling to invisible position

      float fcviY = findViewByPosition(fcvip).getY();
      float lcviY = findViewByPosition(lcvip).getY();

      recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

        int currentState = RecyclerView.SCROLL_STATE_IDLE;

        @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

          if (currentState == RecyclerView.SCROLL_STATE_SETTLING
              && newState == RecyclerView.SCROLL_STATE_IDLE) {

            // recursive scrolling
            smoothScrollToPosition(recyclerView, state, position);
          }

          currentState = newState;
        }

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

          int fcvip = findFirstCompletelyVisibleItemPosition();
          int lcvip = findLastCompletelyVisibleItemPosition();

          if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
            // stop scrolling
            recyclerView.setOnScrollListener(null);
          }
        }
      });

      if (position < fcvip) {
        // scroll up

        recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
      } else {
        // scroll down

        recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
      }
    } else {
      // scrolling to visible position

      float fromY = findViewByPosition(fcvip).getY();
      float targetY = findViewByPosition(position).getY();

      recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
    }
  }
}

तथा

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);

RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

उपरोक्त कोड काम करता है, लेकिन यह चिकना नहीं है और ठंडा नहीं है।


4

यदि आपके पास recyclerView के साथ एडॉप्टर जुड़ा हुआ है तो बस ऐसा करें।

mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());


4

रॉय जवाब एक बड़ी मदद है। मैं इसमें एक छोटा सा ब्लॉक जोड़ना चाहूंगा:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);

4

मेरे मामले में जहां विचारों में समान ऊँचाई नहीं होती है, वहीं लेआउटमैनेजर पर स्क्रॉलटाइपिंग को कॉल करके वास्तव में नीचे तक स्क्रॉल करने और पूरी तरह से अंतिम आइटम देखने का काम किया:

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);

2

यह मेरे लिए पूरी तरह से ठीक काम करता है:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);

2

पहली बार स्क्रॉल करें जब पहली बार पुनर्नवीनीकरण दृश्य में प्रवेश करें तो उपयोग करें

linearLayoutManager.scrollToPositionWithOffset(messageHashMap.size()-1

सकारात्मक मूल्य में स्क्रॉल अप के लिए नीचे स्क्रॉल करने के लिए माइनस में डालें);

यदि दृश्य ऊंचाई में बहुत बड़ा है तो स्क्रॉलटॉपटॉप विशेष ऑफसेट का उपयोग दृश्य के शीर्ष के लिए किया जाता है, फिर आप उपयोग करते हैं

int overallXScroldl =chatMessageBinding.rvChat.computeVerticalScrollOffset();
chatMessageBinding.rvChat.smoothScrollBy(0, Math.abs(overallXScroldl));

0

केवल इयान का उत्तर मेरी RecyclerViewस्क्रॉल को एक निर्दिष्ट स्थिति में लाने में सक्षम था । हालाँकि, RecyclerViewजब मैं उपयोग करता था तो बाद में स्क्रॉल नहीं कर पाता था scrollToPosition()smoothScrollToPosition()काम किया लेकिन प्रारंभिक एनीमेशन ने इसे बहुत धीमा कर दिया जब सूची लंबी थी। कारण यह था कि श्रोता को हटाया नहीं गया था। मैंने वर्तमान को हटाने के लिए नीचे दिए गए कोड का उपयोग किया ViewTreeObserverऔर इसने एक आकर्षण के रूप में काम किया।

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

0

यह कोड आपको पहले नवीनतम पोस्ट देगा, मुझे लगता है कि यह उत्तर सहायक है।

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
    mInstaList.setHasFixedSize(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    mInstaList.setLayoutManager(layoutManager);
    layoutManager.setStackFromEnd(true);
    layoutManager.setReverseLayout(true);

0

@Galex की एक विधि की कोशिश की , यह refactoring तक काम किया। इसलिए मैंने @yanchenko का जवाब दिया और थोड़ा बदल गया। संभवतः ऐसा इसलिए है क्योंकि मैंने स्क्रॉलिंग को कहा है onCreateView(), जहां एक खंड दृश्य बनाया गया था (और शायद सही आकार नहीं था)।

private fun scrollPhotosToEnd(view: View) {
    view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
        ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            } else {
                @Suppress("DEPRECATION")
                view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
            }
            adapter?.itemCount?.takeIf { it > 0 }?.let {
                view.recycler_view.scrollToPosition(it - 1)
            }
        }
    })
}

आप viewTreeObserver.isAliveजैसे https://stackoverflow.com/a/39001731/2914140 का चेक भी जोड़ सकते हैं ।


0

यदि इनमें से कोई भी काम नहीं किया,

आपको उपयोग करने का प्रयास करना चाहिए:

ConstraintLayout targetView = (ConstraintLayout) recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount()-1).itemView;
targetView.getParent().requestChildFocus(targetView, targetView);

ऐसा करने से, आप एक निश्चित कांस्ट्रेन्डलैट का अनुरोध कर रहे हैं (या आपके पास जो कुछ भी है) प्रदर्शित होने के लिए। स्क्रॉल तुरंत है।

मैं दिखाए गए कीबोर्ड से भी काम करता हूं।

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