RecyclerView को समझनाहैसफिक्सडाइज सेट करें


136

मुझे समझने में थोड़ी परेशानी हो रही है setHasFixedSize()। मुझे पता है कि यह RecyclerViewडॉक्स से, जब आकार नहीं बदलता है, तो अनुकूलन के लिए उपयोग किया जाता है ।

हालांकि इसका क्या मतलब है? ज्यादातर सामान्य मामलों में ListViewलगभग हमेशा एक निश्चित आकार होता है। किन मामलों में यह एक निश्चित आकार नहीं होगा? क्या इसका मतलब यह है कि स्क्रीन पर रहने वाली वास्तविक अचल संपत्ति सामग्री के साथ बढ़ती है?



मैंने पाया कि यह उत्तर सहायक और समझने में बहुत आसान है [StackOverflow - rv.setHasFixedSize (true); ] ( stackoverflow.com/questions/28827597/… )
मुस्तफा हसन

जवाबों:


115

RecyclerView का एक बहुत ही सरल संस्करण है:

void onItemsInsertedOrRemoved() {
   if (hasFixedSize) layoutChildren();
   else requestLayout();
}

यह लिंक बताता है कि कॉलिंग requestLayoutमहंगी क्यों हो सकती है। मूल रूप से जब भी आइटम डाले जाते हैं, तो RecyclerView का आकार (चौड़ाई और ऊंचाई) बदल दिया जाता है या हटा दिया जाता है और बदले में दृश्य पदानुक्रम में किसी अन्य दृश्य का आकार बदल सकता है। यह विशेष रूप से परेशानी है यदि आइटम अक्सर जोड़े या हटाए जाते हैं।

setHasFixedSizeएडेप्टर की सामग्री को बदलते समय यह सही या चौड़ाई में नहीं बदलता है, यह तय करके अनावश्यक लेआउट पास से बचें ।


अद्यतन: JavaDoc को बेहतर तरीके से वर्णन करने के लिए अद्यतन किया गया है कि विधि वास्तव में क्या करती है।

RecyclerView कई अनुकूलन कर सकता है यदि यह पहले से पता कर सकता है कि RecyclerView का आकार एडेप्टर सामग्री से प्रभावित नहीं है। RecyclerView अभी भी अन्य कारकों (जैसे उसके माता-पिता के आकार) के आधार पर अपने आकार को बदल सकता है, लेकिन यह आकार गणना अपने बच्चों के आकार या उसके एडॉप्टर की सामग्री (एडॉप्टर में आइटमों की संख्या को छोड़कर) पर निर्भर नहीं कर सकती है।

यदि आपका RecyclerView का उपयोग इस श्रेणी में आता है, तो इसे {@code true} पर सेट करें। यह RecyclerView को इसकी एडॉप्टर सामग्री बदलने पर पूरे लेआउट को अमान्य करने से बचने की अनुमति देगा।

अगर एडेप्टर में बदलाव रिसायकलर व्यू के आकार को प्रभावित नहीं कर सकता है तो @param ने इसे सही बनाया है।


162
हर बार जब आप कुछ जोड़ते हैं तो RecyclerView का आकार बदलता है। SetHasFixedSize क्या करता है कि यह सुनिश्चित करता है (उपयोगकर्ता इनपुट द्वारा) कि RecyclerView के आकार का यह परिवर्तन निरंतर है। आइटम की ऊंचाई (या चौड़ाई) नहीं बदलेगी। जोड़ा या हटाया गया हर सामान समान होगा। यदि आप इसे सेट नहीं करते हैं, तो यह जांच करेगा कि क्या आइटम का आकार बदल गया है और महंगा है। सिर्फ स्पष्ट करना क्योंकि यह उत्तर भ्रमित करने वाला है।
अर्नोल्ड बल्लियू

9
@AnnoldB उत्कृष्ट स्पष्टीकरण। मैं इसे एक स्टैंडअलोन जवाब के रूप में भी तर्क दूंगा।
young_souvlaki

4
@AnnoldB - मैं अभी भी भ्रमित हूँ। क्या आप यह सुझाव दे रहे हैं कि अगर सभी बच्चों की चौड़ाई / ऊँचाई स्थिर है, तो हमें सही-सही निर्धारित करना चाहिए? यदि हाँ, तो क्या होगा यदि ऐसी संभावना है कि कुछ बच्चों को रनटाइम पर हटाया जा सकता है (मेरे पास एक बर्खास्तगी की सुविधा है) - क्या यह सही है?
जगुआर

1
हाँ। क्योंकि आइटम की चौड़ाई और ऊंचाई नहीं बदल रही है। इसे बस जोड़ा या हटाया जा रहा है। आइटम जोड़ने या हटाने से उनका आकार नहीं बदलता है।
अर्नोल्ड बल्लियू

3
@ArnoldB मुझे नहीं लगता कि आइटम का आकार (चौड़ाई / ऊँचाई) यहाँ एक समस्या है। यह आइटम के आकार की जाँच नहीं करेगा। यह सिर्फ requestLayoutDataSet अपडेट होने के बाद RecyclerView को कॉल करने या न करने के लिए कहता है।
किमी चिउ

22

पुष्टि कर सकते हैं setHasFixedSizeखुद से संबंधित RecyclerView, न कि प्रत्येक आइटम का आकार इसके लिए अनुकूलित।

अब आप android:layout_height="wrap_content"एक RecyclerView पर उपयोग कर सकते हैं , जो अन्य बातों के अलावा, CollapsingToolbarLayout को यह जानने की अनुमति देता है कि RecyclerView के खाली होने पर इसे गिरना नहीं चाहिए। यह केवल तब काम करता है जब आप setHasFixedSize(false)RecylcerView पर उपयोग करते हैं।

यदि आप setHasFixedSize(true)RecyclerView पर उपयोग करते हैं, तो CollapsingToolbarLayout को टकराने से रोकने के लिए यह व्यवहार काम नहीं करता है, भले ही RecyclerView वास्तव में खाली हो।

यदि setHasFixedSizeआइटम के आकार से संबंधित था, तो इसका कोई प्रभाव नहीं होना चाहिए जब RecyclerView में कोई आइटम नहीं है।


4
मेरे पास बस एक अनुभव है जो एक ही दिशा की ओर इशारा करता है। एक GridLayoutManager (प्रति पंक्ति 3 आइटम) और लेआउट_हाइट = wra_content के साथ RecyclerView का उपयोग करना। जब मैं सूची में 3 नए आइटम जोड़ने वाले बटन पर क्लिक करता हूं, तो नए आइटम को फिट करने के लिए रिसाइकलर दृश्य का विस्तार नहीं होता है। बल्कि, यह उसी आकार को बनाए रखता है, और नई वस्तुओं को देखने का एकमात्र तरीका इसे स्क्रॉल करना है। हालाँकि आइटमों का आकार समान है, फिर भी मुझे setHasFixedSize(true)नए आइटम जोड़ने पर इसे विस्तारित करने के लिए निकालना पड़ा ।
मट्टुस गोंडिम

मुझे लगता है कि आप सही हैं। दस्तावेज़ से, hasFixedSize: set to true if adapter changes cannot affect the size of the RecyclerView.इसलिए भले ही आइटम का आकार बदल जाएगा, फिर भी आप इसे सही पर सेट कर सकते हैं।
किमी चिउ

12

ListView का एक समान नाम वाला फ़ंक्शन था जो मुझे लगता है कि व्यक्तिगत सूची आइटम हाइट्स के आकार के बारे में जानकारी को प्रतिबिंबित करता था। RecyclerView के लिए प्रलेखन बहुत स्पष्ट रूप से बताता है कि यह RecyclerView के आकार की ही बात कर रहा है, इसके आइटमों के आकार की नहीं।

RecHlerView से स्रोत से ऊपर setHasFixedSize () विधि:

 * RecyclerView can perform several optimizations if it can know in advance that changes in
 * adapter content cannot change the size of the RecyclerView itself.
 * If your use of RecyclerView falls into this category, set this to true.

16
लेकिन RecyclerView के "आकार" को कैसे परिभाषित किया गया है? क्या यह केवल स्क्रीन पर दिखाई देने वाला आकार है, या RecyclerView का पूर्ण आकार है, जो बराबर (आइटम हाइट्स + पेडिंग + रिक्ति का योग) है?
विक्की चिजवानी

2
वास्तव में, यह अधिक जानकारी की जरूरत है। यदि आप आइटम हटाते हैं और recyclerview सिकुड़ता है, तो क्या यह माना जाता है कि इसका आकार बदल गया था?
हेनरिक डी सोसा

4
मैं इसके बारे में सोचता हूं कि कैसे एक TextView खुद को बाहर कर सकता है। यदि आप wra_content निर्दिष्ट करते हैं, तो जब आप पाठ सेट करते हैं तो TextView एक लेआउट पास का अनुरोध कर सकता है और स्क्रीन पर इसके स्थान की मात्रा को बदल सकता है। यदि आप match_parent या एक निश्चित आयाम निर्दिष्ट करते हैं, तो TextView एक लेआउट पास का अनुरोध नहीं करेगा क्योंकि आकार तय हो गया है और पाठ insde की मात्रा कभी भी कब्जे वाले स्थान की मात्रा को नहीं बदलेगी। RecyclerView समान है। setHasFixedSize () आरवी को संकेत देता है कि इसे एडॉप्टर आइटम में परिवर्तन के आधार पर लेआउट पास का अनुरोध करने की आवश्यकता नहीं होनी चाहिए।
डांगवार्मिट

1
@dangVarmit अच्छा स्पष्टीकरण!
होवरकैन

6

वेन हम उस setHasFixedSize(true)पर सेट RecyclerViewकरते हैं इसका मतलब है कि पुनर्नवीनीकरण का आकार तय हो गया है और एडेप्टर सामग्री से प्रभावित नहीं है। और इस मामले onLayoutमें रिसाइकलर पर नहीं बुलाया जाता है जब हम एडेप्टर के डेटा को अपडेट करते हैं (लेकिन एक अपवाद है)।

आइए उदाहरण के लिए चलते हैं:

RecyclerViewएक है RecyclerViewDataObserver( इस फ़ाइल में खोजने डिफ़ॉल्ट implemntation कई तरीके के साथ), मुख्य रूप से महत्वपूर्ण है:

void triggerUpdateProcessor() {
    if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
        ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
    } else {
        mAdapterUpdateDuringMeasure = true;
        requestLayout();
    }
}

अगर हम सेट इस विधि कहा जाता है setHasFixedSize(true)के माध्यम से और एक एडाप्टर के डेटा को अद्यतन: notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved or notifyItemRangeMoved। इस मामले में रिसाइकलर के लिए कोई कॉल नहीं है onLayout, लेकिन requestLayoutचिल्ड को अपडेट करने के लिए कॉल है ।

लेकिन अगर हम setHasFixedSize(true)एक एडॉप्टर के डेटा को सेट और अपडेट करते हैं, notifyItemChangedतो onChangeरिसाइकलर के डिफॉल्ट में RecyclerViewDataObserverकॉल होता है और कोई कॉल नहीं होता है triggerUpdateProcessor। इस मामले में recycler onLayoutकहा जाता है जब भी हम सेट setHasFixedSize trueया false

// no calls to triggerUpdateProcessor
@Override
public void onChanged() {
    assertNotInLayoutOrScroll(null);
     mState.mStructureChanged = true;

     processDataSetCompletelyChanged(true);
     if (!mAdapterHelper.hasPendingUpdates()) {
         requestLayout();
     }
}

// calls to triggerUpdateProcessor
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
    assertNotInLayoutOrScroll(null);
    if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
        triggerUpdateProcessor();
    }
}

अपने आप से कैसे जांचें:

कस्टम बनाएँ RecyclerViewऔर ओवरराइड करें:

override fun requestLayout() {
    Log.d("CustomRecycler", "requestLayout is called")
    super.requestLayout()
}

override fun invalidate() {
    Log.d("CustomRecycler", "invalidate is called")
    super.invalidate()
}

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
    Log.d("CustomRecycler", "onLayout is called")
    super.onLayout(changed, l, t, r, b)
}

match_parent(Xml में) पुनर्नवीनीकरण आकार सेट करें । एडेप्टर के डेटा का उपयोग करके replaceDataऔर सेट करने के replaceOne साथ setHasFixedSize(true)और फिर अपडेट करने का प्रयास करें false

// onLayout is called every time
fun replaceAll(data: List<String>) {
    dataSet.clear()
    dataSet.addAll(data)
    this.notifyDataSetChanged()
}

// onLayout is called only for setHasFixedSize(false)
fun replaceOne(data: List<String>) {
    dataSet.removeAt(0)
    dataSet.addAll(0, data[0])
    this.notifyItemChanged(0)
}

और अपना लॉग चेक करें।

मेरा लॉग:

// for replaceAll
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onMeasure is called
D/CustomRecycler: onLayout
D/CustomRecycler: requestLayout is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called

// for replaceOne
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called
D/CustomRecycler: requestLayout is called
D/CustomRecycler: onDraw is called

संक्षेप:

यदि हम setHasFixedSize(true)कॉल करने के अलावा किसी अन्य तरीके से पर्यवेक्षक को सूचित करने के साथ एडॉप्टर के डेटा को सेट और अपडेट करते हैं notifyDataSetChanged, तो आपके पास कुछ पूर्णता है, क्योंकि रिसाइकलर onLayoutविधि के लिए कोई कॉल नहीं है ।


क्या आपने wra_content या match_parent का उपयोग करके ऊँचाई के RecyclerView के साथ परीक्षण किया था?
ल्यूबोस मुद्रक

6

हम एक है, तो RecyclerViewसाथ match_parentके रूप में ऊंचाई / चौड़ाई , हम जोड़ने चाहिए setHasFixedSize(true)के आकार के बाद से RecyclerViewही लगाते या इसे में आइटम हटाते नहीं बदलता है।

setHasFixedSize अगर हम साथ एक RecyclerView है झूठी होना चाहिए wrap_contentके रूप में ऊंचाई / चौड़ाई प्रत्येक तत्व अनुकूलक द्वारा डाला के आकार को बदल सकता है के बाद से Recyclerशामिल किए गए आइटम पर निर्भर करता है / नष्ट कर दिया है, इसलिए, के आकार Recyclerहर बार अलग होगा हम जोड़ना / हटाना आइटम नहीं है।

अधिक स्पष्ट होने के लिए, यदि हम उपयोग करते हैं

<android.support.v7.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

हम प्रयोग कर सकते हैं my_recycler_view.setHasFixedSize(true)

<android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

हमें उपयोग करना चाहिए my_recycler_view.setHasFixedSize(false), यह लागू होता है यदि हम wrap_contentचौड़ाई के रूप में भी उपयोग करते हैं


3

setHasFixedSize (सच) का मतलब है कि RecyclerView में बच्चे (आइटम) हैं जिनकी चौड़ाई और ऊंचाई तय है। यह RecyclerView को आपके एडॉप्टर के आधार पर पूरी सूची की सटीक ऊंचाई और चौड़ाई का पता लगाकर बेहतर अनुकूलन करने की अनुमति देता है।


5
ऐसा नहीं है कि @dangVarmit ने सुझाव दिया है।
अजनबी

5
भ्रामक, यह वास्तव में रिसाइकलर का आकार है, सामग्री का आकार नहीं
बेनोइट

0

यह recyclerview के एनिमेशन को प्रभावित करता है, अगर यह है false.. सम्मिलित करें और निकालें एनिमेशन नहीं दिखाएंगे। इसलिए सुनिश्चित करें कि यह trueमामले में आपने recyclerview के लिए एनीमेशन जोड़ा है।


0

यदि RecyclerView का आकार (RecyclerView ही)

... एडेप्टर सामग्री पर निर्भर नहीं करता है:

mRecyclerView.setHasFixedSize(true);

... एडेप्टर सामग्री पर निर्भर करता है:

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