स्क्रॉलव्यू के अंदर RecyclerView काम नहीं कर रहा है


276

मैं एक लेआउट को लागू करने की कोशिश कर रहा हूं जिसमें एक ही लेआउट में RecyclerView और स्क्रॉल दृश्य शामिल हैं।

लेआउट टेम्पलेट:

<RelativeLayout>
    <ScrollView android:id="@+id/myScrollView">
       <unrelated data>...</unrealated data>

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


</RelativeLayout>

समस्याएं: मैं अंतिम तत्व तक स्क्रॉल कर सकता हूं ScrollView

मैंने जिन चीजों की कोशिश की:

  1. ScrollView(अब ScrollViewसम्‍मिलित RecyclerView) के अंदर कार्ड दृश्य - कार्ड को तब तक देख सकते हैं जब तकRecyclerView
  2. आरंभिक विचार यह था कि इसका viewGroupउपयोग RecyclerViewकरने के बजाय इसे लागू करने के लिए, ScrollViewजहां से यह एक प्रकार का विचार है, CardViewलेकिन मुझे इसके समान सटीक परिणाम मिलेScrollView

इस दृष्टिकोण की जाँच करें: stackoverflow.com/a/21878703/684582
Alécio Carvalho

15
इन मामलों में से कई में एक सरल समाधान NestedScrollViewइसके बजाय उपयोग करना है, क्योंकि यह बहुत सारे स्क्रॉलिंग मुद्दों को संभालता है
रिचर्ड ले मेसुरियर

रिचर्ड ने आपको इसका जवाब फरवरी में दिया था। के NestedScrollViewबजाय का उपयोग करें ScrollView। वास्तव में यही है।
माइक एम।

2
मेरे लिए एक चीज़ नहीं बदलती।
ल्यूक एलिसन

2
भविष्य के संदर्भ के लिए, यदि किसी को केवल marshmallow / nougat (API 23, 24) डिवाइस में समान समस्या का सामना करना पड़ रहा है, तो stackoverflow.com/a/38995399/132121
हुसैन खान

जवाबों:


653

के NestedScrollViewबजाय का उपयोग करेंScrollView

कृपया अधिक जानकारी के लिए NestedScrollView संदर्भ दस्तावेज़ देखें।

और recyclerView.setNestedScrollingEnabled(false);अपने को जोड़ेंRecyclerView


24
के साथ काम करता है: android.support.v4.widget.NestedScrollView
Cocorico

7
android:layout_height="wrap_content"ViewHolder के लिए फुलाए गए लेआउट के लिए रखें
सारथ बाबू

4
NestedScrollViewमेरे विपरीत एक जटिल लेआउट में, के विपरीत ScrollViewNestedScrollView
रोमन Samoylenko

7
इसके अलावा आप android जोड़ सकते हैं: nestedScrollingEnabled = "false" के बजाय XML में recyclerView.setNestedScrollingEnabled (गलत);
kostyabakay

2
इसने मेरे लिए काम किया लेकिन ध्यान रखें कि रिसाइक्लरव्यू के अंदर की वस्तुओं को रिसाइकल नहीं किया जा रहा है।
मुस्तफा अरियन नेजाद

102

मुझे पता है कि मुझे देर हो गई है यह खेल है, लेकिन यह मुद्दा अभी भी मौजूद है क्योंकि Google ने भी इस पर ठीक किया है android.support.v7.widget.RecyclerView

अब मुझे जो मुद्दा मिलता है RecyclerView, layout_height=wrap_contentवह अंदर के सभी आइटमों की ऊँचाई नहीं लेने के साथ है ScrollViewजो केवल मार्शमैलो और नूगट + (एपीआई 23, 24, 25) संस्करणों पर होता है।
(अद्यतन: सभी संस्करणों पर कामों के ScrollViewसाथ प्रतिस्थापित करना android.support.v4.widget.NestedScrollView। मैं किसी भी तरह से स्वीकृत समाधान का परीक्षण करने से चूक गया। इसे डेमो की तरह मेरे गितूब प्रोजेक्ट में जोड़ा गया।)

अलग-अलग चीजों की कोशिश करने के बाद, मुझे इस समस्या को हल करने वाला वर्कअराउंड मिला है।

यहाँ संक्षेप में मेरी लेआउट संरचना है:

<ScrollView>
  <LinearLayout> (vertical - this is the only child of scrollview)
     <SomeViews>
     <RecyclerView> (layout_height=wrap_content)
     <SomeOtherViews>

वर्कअराउंड के RecyclerViewसाथ लपेटो है RelativeLayout। मुझे मत पूछो कि मुझे यह कैसे मिला!¯\_(ツ)_/¯

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

पूरा उदाहरण GitHub परियोजना पर उपलब्ध है - https://github.com/amardeshbd/android-recycler-view-wrap-content

यहां एक डेमो स्क्रैंकास्ट दिखाया गया है, जो कार्रवाई को ठीक कर रहा है:

स्क्रीनकास्ट


6
धन्यवाद आदमी .. इसकी बहुत मदद .. लेकिन आपके समाधान के बाद स्क्रॉल करना मुश्किल हो जाता है इसलिए मैंने recyclerview.setNestedScrollingEnabled (गलत) सेट किया; और अब एक आकर्षण की तरह इसका काम।
सागर चावड़ा

4
क्या यह विधि विचारों को रीसायकल करती है? अगर हमारे पास लगभग सैकड़ों ऑब्जेक्ट रीसायकल होने हैं। यह हैक नहीं समाधान है।
androidXP

1
हां, @androidXP सही है, यह हैक लंबी सूची का हल नहीं है। मेरा उपयोग मामला एक सूची दृश्य में आइटम तय किया गया था, जो 10. से कम था और जैसा कि मैंने दूसरे वर्कअराउंड को पाया, मैं यादृच्छिक चीजों की कोशिश कर रहा था, यह उनमें से एक था :-)
हुसैन खान

adnroid मार्शमैलो और ऊपरी में perfect.solved मेरी समस्या। ;)
अमीर ज़ियारती

2
यदि मैं इस समाधान का उपयोग करता हूं, तो onBindView को सूची में सभी वस्तुओं के लिए बुलाया जा रहा है, जो कि recyclerview का उपयोग नहीं है।
thedarkpassenger

54

हालांकि सिफारिश है कि

आपको कभी भी स्क्रॉल करने योग्य दृश्य को किसी अन्य स्क्रॉल करने योग्य दृश्य के अंदर नहीं रखना चाहिए

एक ध्वनि सलाह है, हालांकि अगर आप रिसाइकलर दृश्य पर एक निश्चित ऊंचाई निर्धारित करते हैं तो इसे ठीक काम करना चाहिए।

यदि आप एडॉप्टर आइटम लेआउट की ऊंचाई जानते हैं तो आप RecyclerView की ऊंचाई की गणना कर सकते हैं।

int viewHeight = adapterItemSize * adapterData.size();
recyclerView.getLayoutParams().height = viewHeight;

10
कैसे प्राप्त करें?
कार्तिक

1
यह एक सम्मोहन की तरह काम करता है! थोड़ा सुधार यह होना चाहिए: int viewHeight = adapterItemSize * अनुकूलकData.size (); recyclerView.getLayoutParams ()। height = viewHeight;
वैभव जानी

3
एडेप्टर कैसे पता लगाएं?
droidster.me

2
@JoakimEngstrom adapterItemSizeचर क्या है ?
इगोरगानापोलस्की

1
स्क्रॉल दृश्य के अंदर रिसाइकलर दृश्य से बचें, क्योंकि स्क्रॉल दृश्य उसके बच्चे को अनंत स्थान देते हैं। यह पुनरावर्तक दृश्य को लंबवत दिशा (असीम दृश्य के अंतिम आइटम तक) में असीम रूप से मापने के लिए ऊँचाई के रूप में wra_content होने का कारण बनता है। स्क्रॉल दृश्य के अंदर पुनर्नवीनीकरण दृश्य का उपयोग करने के बजाय, विभिन्न आइटम प्रकारों के साथ केवल पुनर्नवीनीकरण दृश्य का उपयोग करें। इस कार्यान्वयन के साथ, स्क्रॉल दृश्य के बच्चे दृश्य प्रकार के रूप में व्यवहार करेंगे। उन दृश्यदर्शी को पुनर्नवीनीकरण दृश्य के अंदर संभालें।
अभिषेक २५'१६

28

मामले में RecyclerView के लिए निश्चित ऊंचाई निर्धारित करने के लिए किसी (मेरे जैसे) के लिए काम नहीं किया, यहाँ है कि मैं तय ऊंचाई समाधान में जोड़ा गया है:

mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        int action = e.getAction();
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                rv.getParent().requestDisallowInterceptTouchEvent(true);
                break;
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
});

1
वास्तव में, यह मेरे लिए अच्छा था। इस जगह के साथ, मैं स्क्रॉल दृश्य को ऊपर और नीचे ले जाने में सक्षम था, और जब मैं स्क्रॉल करने के लिए रिसाइक्लेव्यू का चयन करता हूं, तो यह स्क्रॉल दृश्य पर प्राथमिकता लेता है। टिप के लिए धन्यवाद
PGMacDesign

1
इसने मेरे लिए भी काम किया, बस स्क्रोलव्यू के सीधे बच्चे पर गेटपेंट का उपयोग करना सुनिश्चित करें
BigBen3216

यह विधि सायनोजेनमॉड वितरण पर भी काम करती है। सियानोजेनमॉड पर निर्धारित ऊंचाई का समाधान काम करता है, लेकिन केवल तभी यदि निर्धारित ऊंचाई सूची में सभी वस्तुओं की पूर्ण ऊंचाई है, जो पहले स्थान पर पुनरावर्तन का उपयोग करने के बिंदु को परिभाषित करता है। Upvoted।
HappyKatz

मुझे भी recyclerView.setNestedScrollingEnabled (झूठा) की आवश्यकता थी;
एनालिस्ट

25

नई एंड्रॉइड सपोर्ट लाइब्रेरी 23.2 उस समस्या को हल करती है, अब आप अपने काम की ऊंचाई के रूप में रैप_ कॉन्टेंट सेट कर सकते हैं RecyclerViewऔर सही ढंग से काम कर सकते हैं।

एंड्रॉइड सपोर्ट लाइब्रेरी 23.2


ठीक से भी लात नहीं करता है (23.4.0)
behelit

1
@behelit 23.4.0 में कुछ समस्याएँ हैं। code.google.com/p/android/issues/detail?id=210085#makechanges , इसके बजाय 23.2.1 का उपयोग करें
Samad

1
२५.०.१ पर भी ठीक से नहीं चलती है
मारुति ०६०३ 2५

15

जब तक वे खुद को स्क्रॉल नहीं कर रहे हैं तब तक RecyclerViews को स्क्रॉल-व्यू में डालना ठीक है। इस मामले में, यह एक निश्चित ऊंचाई बनाने के लिए समझ में आता है।

उचित समाधान wrap_contentRecyclerView ऊँचाई पर उपयोग करना है और फिर एक कस्टम LinearLayoutManager को लागू करना है जो रैपिंग को ठीक से संभाल सकता है।

अपने प्रोजेक्ट में इस LinearLayoutManager को कॉपी करें: https://github.com/sero/android-linear-layout-manager/blob/master/lib/src/main/java/org/solovitv/android/views/llm/LinearLayoutManager.java

फिर RecyclerView को लपेटें:

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

और इसे ऐसे सेट करें:

    RecyclerView list = (RecyclerView)findViewById(R.id.list);
    list.setHasFixedSize(true);
    list.setLayoutManager(new com.example.myapp.LinearLayoutManager(list.getContext()));
    list.setAdapter(new MyViewAdapter(data));

संपादित करें: यह स्क्रॉलिंग के साथ जटिलताएं पैदा कर सकता है क्योंकि RecyclerView स्क्रॉलव्यू की स्पर्श घटनाओं को चुरा सकता है। मेरा समाधान बस सभी में RecyclerView को खोदने और LinearLayout के साथ जाने के लिए था, प्रोग्रामेटिक रूप से सबव्यू को फुलाकर, और उन्हें लेआउट में जोड़ें।


4
क्या आप recyclerview पर setNestedScrollingEnabled (गलत) कॉल नहीं कर सके?
एशान

14

इसके लिए ScrollView, आप नीचे दिए अनुसार उपयोग कर सकते हैं fillViewport=trueऔर layout_height="match_parent"पुनर्नवीनीकरण दृश्य डाल सकते हैं:

<ScrollView
    android:fillViewport="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/llOptions">
          <android.support.v7.widget.RecyclerView
            android:id="@+id/rvList"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
</ScrollView>

कोड के माध्यम से कोई और अधिक ऊंचाई समायोजन की आवश्यकता नहीं है।


V23.2.1 का उपयोग करके परीक्षण किए गए ठीक काम। इसका इस्तेमाल रिसाइकलव्यू के ऊपर लेआउट जोड़ने के लिए कर रहा था।
winontan520

सिर्फ RecyclerView स्क्रॉलिंग और स्क्रॉल नहीं स्क्रॉल करना
Samad

13

RecyclerViewमैन्युअल रूप से ऊंचाई की गणना करना अच्छा नहीं है, कस्टम का उपयोग करना बेहतर है LayoutManager

(ऊपर जारी करने के लिए कारण किसी भी दृश्य है जो यह की पुस्तक है ListView, GridView, RecyclerView) यह की ऊंचाई की गणना करने के लिए जब एक और दृश्य में एक बच्चे के रूप ऐड पुस्तक है विफल रहा है। अतः इसके अधिपतिonMeasure विधि को करने से समस्या हल हो जाएगी।

कृपया नीचे के साथ डिफ़ॉल्ट लेआउट प्रबंधक बदलें:

public class MyLinearLayoutManager extends android.support.v7.widget.LinearLayoutManager {

private static boolean canMakeInsetsDirty = true;
private static Field insetsDirtyField = null;

private static final int CHILD_WIDTH = 0;
private static final int CHILD_HEIGHT = 1;
private static final int DEFAULT_CHILD_SIZE = 100;

private final int[] childDimensions = new int[2];
private final RecyclerView view;

private int childSize = DEFAULT_CHILD_SIZE;
private boolean hasChildSize;
private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS;
private final Rect tmpRect = new Rect();

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context) {
    super(context);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view) {
    super(view.getContext());
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) {
    super(view.getContext(), orientation, reverseLayout);
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

public void setOverScrollMode(int overScrollMode) {
    if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER)
        throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode);
    if (this.view == null) throw new IllegalStateException("view == null");
    this.overScrollMode = overScrollMode;
    ViewCompat.setOverScrollMode(view, overScrollMode);
}

public static int makeUnspecifiedSpec() {
    return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);

    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);

    final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED;
    final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED;

    final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
    final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;

    final int unspecified = makeUnspecifiedSpec();

    if (exactWidth && exactHeight) {
        // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
        super.onMeasure(recycler, state, widthSpec, heightSpec);
        return;
    }

    final boolean vertical = getOrientation() == VERTICAL;

    initChildDimensions(widthSize, heightSize, vertical);

    int width = 0;
    int height = 0;

    // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
    // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
    // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
    // called whiles scrolling)
    recycler.clear();

    final int stateItemCount = state.getItemCount();
    final int adapterItemCount = getItemCount();
    // adapter always contains actual data while state might contain old data (f.e. data before the animation is
    // done). As we want to measure the view with actual data we must use data from the adapter and not from  the
    // state
    for (int i = 0; i < adapterItemCount; i++) {
        if (vertical) {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, widthSize, unspecified, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            height += childDimensions[CHILD_HEIGHT];
            if (i == 0) {
                width = childDimensions[CHILD_WIDTH];
            }
            if (hasHeightSize && height >= heightSize) {
                break;
            }
        } else {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, unspecified, heightSize, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            width += childDimensions[CHILD_WIDTH];
            if (i == 0) {
                height = childDimensions[CHILD_HEIGHT];
            }
            if (hasWidthSize && width >= widthSize) {
                break;
            }
        }
    }

    if (exactWidth) {
        width = widthSize;
    } else {
        width += getPaddingLeft() + getPaddingRight();
        if (hasWidthSize) {
            width = Math.min(width, widthSize);
        }
    }

    if (exactHeight) {
        height = heightSize;
    } else {
        height += getPaddingTop() + getPaddingBottom();
        if (hasHeightSize) {
            height = Math.min(height, heightSize);
        }
    }

    setMeasuredDimension(width, height);

    if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) {
        final boolean fit = (vertical && (!hasHeightSize || height < heightSize))
                || (!vertical && (!hasWidthSize || width < widthSize));

        ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS);
    }
}

private void logMeasureWarning(int child) {
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
                "To remove this message either use #setChildSize() method or don't run RecyclerView animations");
    }
}

private void initChildDimensions(int width, int height, boolean vertical) {
    if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
        // already initialized, skipping
        return;
    }
    if (vertical) {
        childDimensions[CHILD_WIDTH] = width;
        childDimensions[CHILD_HEIGHT] = childSize;
    } else {
        childDimensions[CHILD_WIDTH] = childSize;
        childDimensions[CHILD_HEIGHT] = height;
    }
}

@Override
public void setOrientation(int orientation) {
    // might be called before the constructor of this class is called
    //noinspection ConstantConditions
    if (childDimensions != null) {
        if (getOrientation() != orientation) {
            childDimensions[CHILD_WIDTH] = 0;
            childDimensions[CHILD_HEIGHT] = 0;
        }
    }
    super.setOrientation(orientation);
}

public void clearChildSize() {
    hasChildSize = false;
    setChildSize(DEFAULT_CHILD_SIZE);
}

public void setChildSize(int childSize) {
    hasChildSize = true;
    if (this.childSize != childSize) {
        this.childSize = childSize;
        requestLayout();
    }
}

private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) {
    final View child;
    try {
        child = recycler.getViewForPosition(position);
    } catch (IndexOutOfBoundsException e) {
        if (BuildConfig.DEBUG) {
            Log.w("MyLinearLayoutManager", "MyLinearLayoutManager doesn't work well with animations. Consider switching them off", e);
        }
        return;
    }

    final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();

    final int hPadding = getPaddingLeft() + getPaddingRight();
    final int vPadding = getPaddingTop() + getPaddingBottom();

    final int hMargin = p.leftMargin + p.rightMargin;
    final int vMargin = p.topMargin + p.bottomMargin;

    // we must make insets dirty in order calculateItemDecorationsForChild to work
    makeInsetsDirty(p);
    // this method should be called before any getXxxDecorationXxx() methods
    calculateItemDecorationsForChild(child, tmpRect);

    final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
    final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);

    final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
    final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically());

    child.measure(childWidthSpec, childHeightSpec);

    dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
    dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;

    // as view is recycled let's not keep old measured values
    makeInsetsDirty(p);
    recycler.recycleView(child);
}

private static void makeInsetsDirty(RecyclerView.LayoutParams p) {
    if (!canMakeInsetsDirty) {
        return;
    }
    try {
        if (insetsDirtyField == null) {
            insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty");
            insetsDirtyField.setAccessible(true);
        }
        insetsDirtyField.set(p, true);
    } catch (NoSuchFieldException e) {
        onMakeInsertDirtyFailed();
    } catch (IllegalAccessException e) {
        onMakeInsertDirtyFailed();
    }
}

private static void onMakeInsertDirtyFailed() {
    canMakeInsetsDirty = false;
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect");
    }
}
}

जब हम एडॉप्टर पर डेटा सेट करते हैं तो मैं इस वर्ग को कैसे कॉल कर सकता हूं?
मिलन गजेरा

11

इसे इस्तेमाल करे। बहुत देर से जवाब। लेकिन भविष्य में किसी की मदद जरूर करें।

अपने स्क्रॉलव्यू को NestedScrollView पर सेट करें

<android.support.v4.widget.NestedScrollView>
 <android.support.v7.widget.RecyclerView>
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.NestedScrollView>

अपने Recyclerview में

recyclerView.setNestedScrollingEnabled(false); 
recyclerView.setHasFixedSize(false);

8
NestedScrollView के अंदर RecyclerView का उपयोग करके सूची में प्रत्येक आइटम के लिए onBindView को कॉल कर रहा है, भले ही आइटम दिखाई न दे रहा हो। उस समस्या का कोई समाधान?
थ्रेडार्कजेंसर

8

अद्यतन: यह उत्तर अब दिनांकित है क्योंकि NestedScrollView और RecyclerView जैसे विजेट हैं जो नेस्टेड स्क्रॉलिंग का समर्थन करते हैं।

आपको एक स्क्रॉल करने योग्य दृश्य को किसी अन्य स्क्रॉल करने योग्य दृश्य के अंदर नहीं रखना चाहिए!

मेरा सुझाव है कि आप अपना मुख्य लेआउट पुनर्नवीनीकरण दृश्य बनाएं और अपने विचारों को पुनर्नवीनीकरण दृश्य के आइटम के रूप में रखें।

इस उदाहरण पर एक नज़र डालें कि यह दिखाता है कि रिसाइक्लर व्यू अडैप्टर के अंदर कई दृश्यों का उपयोग कैसे किया जाए। उदाहरण के लिए लिंक


मेरे पास एक से अधिक रीसायकलर वाला पेज है , क्या इसे मनाने का कोई और तरीका है? इंस्टाग्राम या गूगल प्ले पार्ट कमेंट जैसी कुछ बातें जो अधिक टिप्पणी
Ashkan


6
वह बकवास है। तुम ठीक ठीक हो सकता है RecyclerViews नेस्टेड है।
इगोरगानापोलस्की

यह उत्तर अब पुराना हो चुका है। हमारे पास NestedScrollView जैसी चीजें हैं जो नेस्टेड स्क्रॉल करने योग्य विचारों के लिए अनुमति देती हैं। नेस्टेड RecyclerViews भी अब काम करते हैं।
कोरी हॉर्न

7

यदि आप RecyclerViewअंदर रखते हैं NestedScrollViewऔर सक्षम करते हैं recyclerView.setNestedScrollingEnabled(false);, तो स्क्रॉलिंग अच्छी तरह से काम करेगी ।
हालाँकि, एक समस्या है

RecyclerView रीसायकल न करें

उदाहरण के लिए, आपके RecyclerView(अंदर NestedScrollViewया ScrollView) 100 आइटम हैं।
जब Activityलांच, 100 आइटम पैदा करेगा ( onCreateViewHolderऔर onBindViewHolder100 आइटम के एक ही समय में कहा जाता होगा)।
उदाहरण, प्रत्येक आइटम के लिए, आप एपीआई => बनाई गई गतिविधि से एक बड़ी छवि लोड करेंगे -> 100 छवि लोड होगी।
यह आरंभिक गतिविधि सुस्ती और पिछड़ापन पैदा करता है।
संभावित समाधान :
- RecyclerViewकई प्रकार के उपयोग के बारे में सोचना ।

हालांकि, आपके मामले में अगर, वहाँ बस में कुछ आइटम हैं RecyclerViewऔर रीसायकल या पुनरावृत्ति नहीं है एक बहुत है, तो आप उपयोग कर सकते हैं प्रदर्शन को प्रभावित नहीं करते RecyclerViewअंदर ScrollViewसरल के लिए


दिखाएँ कि मैं कैसे RecyclerView को ScollView के अंदर भी रीसायकल कर सकता हूँ? धन्यवाद!
Liar

2
@ लायर, वर्तमान में RecyclerViewइसे लगाने के बाद रीसायकल बनाने का कोई तरीका नहीं है ScrollView। यदि आप रीसायकल चाहते हैं, तो एक और दृष्टिकोण के बारे में सोच रहे हैं (जैसे कई प्रकार के साथ RecyclerView का उपयोग करना)
फान वान लिन्ह

4

आप इस तरह से उपयोग कर सकते हैं:

इस पंक्ति को अपने recyclerView xml दृश्य में जोड़ें:

        android:nestedScrollingEnabled="false"

यह कोशिश करो, recyclerview लचीली ऊंचाई के साथ आसानी से स्क्रॉल किया जाएगा

आशा है कि इससे मदद मिली।


2

ऐसा लगता है कि NestedScrollViewसमस्या का समाधान करता है। मैंने इस लेआउट का उपयोग करके परीक्षण किया है:

<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/dummy_text"
        />

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        >
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </android.support.v7.widget.CardView>

</LinearLayout>

और यह मुद्दों के बिना काम करता है


Bro, स्टिलव्यू से NestedScrollview में बदले जाने के बाद भी वही समस्‍या है।
मोहनराज एस

एमएमएम ... क्या आप कुछ कोड साझा कर सकते हैं ... मैं शून्य मुद्दे रख रहा हूं, लेकिन यू इस तरह के मुद्दों के साथ कभी नहीं जान सकता है
royB

मैं ईमेल द्वारा या स्टैक ओवरफ्लो के माध्यम से अपना कोड कैसे साझा कर सकता हूं
मोहनराज एस

2
इस कोड का उपयोग सूची में सभी मदों के लिए onBindView को कॉल करता है, भले ही वे आइटम सूची में दिखाई न दें। यह recyclerview के उद्देश्य को पराजित करता है।
थ्रेडार्कजेंसर

2

मैंने RecyclerView स्क्रॉलिंग को अक्षम करने के लिए CustomLayoutManager का उपयोग किया। इसके अलावा WycContent के रूप में Recycler View का उपयोग न करें, इसे 0dp, भार = 1 के रूप में उपयोग करें

public class CustomLayoutManager extends LinearLayoutManager {
    private boolean isScrollEnabled;

    // orientation should be LinearLayoutManager.VERTICAL or HORIZONTAL
    public CustomLayoutManager(Context context, int orientation, boolean isScrollEnabled) {
        super(context, orientation, false);
        this.isScrollEnabled = isScrollEnabled;
    }

    @Override
    public boolean canScrollVertically() {
        //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
        return isScrollEnabled && super.canScrollVertically();
    }
}

RecLlerView में CustomLayoutManager का उपयोग करें:

CustomLayoutManager mLayoutManager = new CustomLayoutManager(getBaseActivity(), CustomLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(mLayoutManager);
        ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); 
        recyclerView.setAdapter(statsAdapter);

यूआई एक्सएमएल:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background_main"
    android:fillViewport="false">


    <LinearLayout
        android:id="@+id/contParentLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <edu.aku.family_hifazat.libraries.mpchart.charts.PieChart
                android:id="@+id/chart1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/x20dp"
                android:minHeight="@dimen/x300dp">

            </edu.aku.family_hifazat.libraries.mpchart.charts.PieChart>


        </FrameLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">


        </android.support.v7.widget.RecyclerView>


    </LinearLayout>


</ScrollView>

2

मुझे भी यही समस्या आ रही थी। यही मैंने कोशिश की और यह काम करता है। मैं अपना xml और जावा कोड साझा कर रहा हूं। आशा है कि यह किसी की मदद करेगा।

यहाँ xml है

<?xml version="1.0" encoding="utf-8"?>

< NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv_thumbnail"
            android:layout_width="match_parent"
            android:layout_height="200dp" />

        <TextView
            android:id="@+id/tv_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Description" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Buy" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Reviews" />
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rc_reviews"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        </android.support.v7.widget.RecyclerView>

    </LinearLayout>
</NestedScrollView >

यहाँ संबंधित जावा कोड है। यह एक सम्मोहन की तरह काम करता है।

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setNestedScrollingEnabled(false);

RecyclerView के नीचे लेआउट के बारे में क्या?
तप

वह भी काम करता है। आपको बस उपयोग करने की आवश्यकता है। NestedScrollViewस्क्रॉल दृश्य के बजाय
जीशान शब्बीर

हां, केवल NestedScrollView। लेकिन NestedScrollView + RecycleView के साथ समाधान RecyclerView की बहुत धीमी आबादी को बुलाता है (मुझे लगता है कि RecyclerView के बाद पहले दृश्य की वाई-स्थिति की कलकत्ता के लिए)
तापा सेव


0

दरअसल का मुख्य उद्देश्य RecyclerViewके लिए क्षतिपूर्ति करने के लिए है ListViewऔर ScrollView। ऐसा करने के बजाय कि आप वास्तव में क्या कर रहे हैं: एक RecyclerViewमें होने के नाते ScrollView, मेरा सुझाव है कि केवल एक ही है RecyclerViewजो कई प्रकार के बच्चों को संभाल सकता है।


1
यह केवल काम करेगा, बशर्ते कि आपके बच्चों को इकट्ठा किया जा सके जैसे ही आप उन्हें स्क्रॉल आउट करेंगे। यदि आपके पास ऐसे बच्चे हैं जो मैपफ्रैगमेंट या स्ट्रीटव्यू हैं, तो इसका कोई मतलब नहीं है क्योंकि वे हर बार फिर से लोड करने के लिए मजबूर होते हैं और वे पुनर्नवीनीकरण करते हैं। एक स्क्रॉलव्यू में एंबेडेड और फिर तल पर एक recyclerview उत्पन्न करने से अधिक समझ में आता है।
सिमोन

1
@Simon वहाँ आसान सेट है () ViewHolder में
ernazm

RecyclerView की सूची ListView की जगह है, यह स्क्रॉल दृश्य को बदलने के लिए नहीं है।
साइरोक्सिस

यह टिप्पणी बेहतर की पात्र है। यह एक समाधान है, और स्वीकृत से भी बेहतर है।
काई वांग

0

पहले आपको NestedScrollViewइसके बजाय उपयोग करना चाहिए ScrollViewऔर RecyclerViewअंदर डालना चाहिएNestedScrollView

स्क्रीन की ऊंचाई और चौड़ाई को मापने के लिए कस्टम लेआउट क्लास का उपयोग करें:

public class CustomLinearLayoutManager extends LinearLayoutManager {

public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        if (getOrientation() == HORIZONTAL) {
            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    heightSpec,
                    mMeasuredDimension);

            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            measureScrapChild(recycler, i,
                    widthSpec,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {
    View view = recycler.getViewForPosition(position);
    recycler.bindViewToPosition(view, position);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
        recycler.recycleView(view);
    }
}
}

और गतिविधि के टुकड़े में नीचे दिए गए कोड को लागू करें RecyclerView:

 final CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);

    recyclerView.setNestedScrollingEnabled(false); // Disables scrolling for RecyclerView, CustomLinearLayoutManager used instead of MyLinearLayoutManager
    recyclerView.setHasFixedSize(false);

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

            int visibleItemCount = layoutManager.getChildCount();
            int totalItemCount = layoutManager.getItemCount();
            int lastVisibleItemPos = layoutManager.findLastVisibleItemPosition();
            Log.i("getChildCount", String.valueOf(visibleItemCount));
            Log.i("getItemCount", String.valueOf(totalItemCount));
            Log.i("lastVisibleItemPos", String.valueOf(lastVisibleItemPos));
            if ((visibleItemCount + lastVisibleItemPos) >= totalItemCount) {
                Log.i("LOG", "Last Item Reached!");
            }
        }
    });

0

यदि RecyclerView स्क्रॉलव्यू के अंदर केवल एक पंक्ति दिखा रहा है। आपको बस अपनी पंक्ति की ऊँचाई निर्धारित करनी है android:layout_height="wrap_content"


0

आप पुनर्नवीनीकरण रोल को सुचारू रूप से बनाने के लिए LinearLayoutManager को भी ओवरराइड कर सकते हैं

@Override
    public boolean canScrollVertically(){
        return false;
    }

0

खेद है कि पार्टी में देर हो रही है, लेकिन ऐसा लगता है कि एक और समाधान है जो आपके द्वारा उल्लिखित मामले के लिए पूरी तरह से काम करता है।

यदि आप एक पुनर्नवीनीकरण दृश्य के अंदर एक पुनर्नवीनीकरण दृश्य का उपयोग करते हैं, तो यह पूरी तरह से ठीक काम करता है। मैंने व्यक्तिगत रूप से कोशिश की है और इसका इस्तेमाल किया है, और यह बिल्कुल धीमेपन और कोई झटके नहीं देता है। अब मुझे यकीन नहीं है कि यह एक अच्छा अभ्यास है या नहीं, लेकिन कई पुनर्नवीनीकरण विचारों को घोंसला बनाना, यहां तक ​​कि नेस्टेड स्क्रॉल दृश्य धीमा हो जाता है। लेकिन यह अच्छी तरह से काम करने लगता है। कृपया इसे एक कोशिश का मौका दीजिए। मुझे यकीन है कि घोंसले के शिकार इस के साथ पूरी तरह से ठीक हो रहा है।


0

एक और दृष्टिकोण मुद्दे का समाधान करने उपयोग करने के लिए है ConstraintLayoutके अंदर ScrollView:

<ScrollView>
  <ConstraintLayout> (this is the only child of ScrollView)
    <...Some Views...>
    <RecyclerView> (layout_height=wrap_content)
    <...Some Other Views...>

लेकिन मैं अभी भी androidx.core.widget.NestedScrollView यांग पेइयोंग द्वारा प्रस्तावित दृष्टिकोण से चिपके रहूंगा


-2

** सॉल्यूशन जो मेरे लिए काम करता है
Use NestedScrollView को wra_content के रूप में ऊंचाई के साथ

<br> RecyclerView 
                android:layout_width="match_parent"<br>
                android:layout_height="wrap_content"<br>
                android:nestedScrollingEnabled="false"<br>
                  app:layoutManager="android.support.v7.widget.LinearLayoutManager"
                tools:targetApi="lollipop"<br><br> and view holder layout 
 <br> android:layout_width="match_parent"<br>
        android:layout_height="wrap_content"

// आपकी पंक्ति सामग्री यहाँ पर जाती है


इसी तरह के उत्तर पर कुछ टिप्पणियां नेस्टेड स्क्रॉलिंग को अक्षम करने से RecyclerView का उपयोग करने के उद्देश्य को पराजित किया जाता है, अर्थात यह दृश्य रीसायकल नहीं करेगा। सुनिश्चित नहीं है कि इसकी पुष्टि कैसे करें।
jk7 १३'१17

1
NestedScrollingEnabled की स्थापना करना = "झूठा" का कारण होता है RecyclerView अपने विचारों को रीसायकल न करना, कम से कम मेरे सेटअप में (एक NycScrollView के अंदर एक RecyclerView)। RecyclerView में एक RecyclerListener को जोड़कर और इसके OnViewRecycled () विधि के अंदर एक विराम बिंदु सेट करके पुष्टि की गई।
jk7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.