ScrollView içindeki RecyclerView çalışmıyor


277

Aynı düzende RecyclerView ve ScrollView içeren bir düzen uygulamaya çalışıyorum.

Düzen şablonu:

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

Sorunlar: öğesinin son öğesine kadar kaydırma yapabilirim ScrollView

Denediğim şeyler:

  1. içerisindeki kart görünümü ScrollView(şimdi ScrollViewiçeriyor RecyclerView) - kartıRecyclerView
  2. ilk düşünce onun görüş türü biri nerede yerine viewGroupkullanarak uygulamak oldu ama ile aynı sonuçları aldımRecyclerViewScrollViewCardViewScrollView


15
Bu durumların çoğunda basit bir çözüm, birçok NestedScrollViewkaydırma sorununu ele aldığı için kullanmaktır
Richard Le Mesurier

Richard cevabı Şubat ayında verdi. Yerine bir NestedScrollViewkullanın ScrollView. Tam olarak bunun için.
Mike M.

2
Benim için hiçbir şeyi değiştirmez.
Luke Allison

2
İleride başvurmak üzere, yalnızca benzer bir sorunla karşılaşan biri sadece hatmi / nuga (API 23, 24) cihazlarında geçici
çözümümü

Yanıtlar:


653

NestedScrollViewyerine kullanScrollView

Daha fazla bilgi için lütfen NestedScrollView referans belgesini inceleyin .

ve eklemek recyclerView.setNestedScrollingEnabled(false);için sizinRecyclerView


24

7
tutmak android:layout_height="wrap_content"ViewHolder için şişirilmiş düzen için
Sarath Babu

4
Karmaşık bir düzende NestedScrollView, aksine benim için gecikiyor ScrollView. Kullanmadan bir çözüm arıyorNestedScrollView
Roman Samoylenko

7
Ayrıca android: recedlerView.setNestedScrollingEnabled (false) yerine XML'e nestedScrollingEnabled = "false" ekleyebilirsiniz;
kostyabakay

2
Benim için çalıştı, ancak recyclerView içindeki öğelerin geri dönüştürülmediğini unutmayın.
Mostafa Arian Nejad

102

Oyuna geç kaldığımı biliyorum, ancak google, android.support.v7.widget.RecyclerView

Şimdi almak konudur RecyclerViewile layout_height=wrap_contentiçindeki tüm öğeler konuyla yüksekliğini almayan ScrollViewo sadece Hatmi ve Nuga + (API 23, 24, 25) sürümlerinde olur.
(GÜNCELLEME: Değiştirme ScrollViewile android.support.v4.widget.NestedScrollViewtüm sürümlerinde eserlerin ben bir şekilde test özledim. Kabul çözüm demo olarak benim github projesinde bu eklendi..)

Farklı şeyler denedikten sonra bu sorunu gideren bir çözüm buldum.

Özetle benim düzen yapısı:

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

Çözüm, sarma RecyclerViewile RelativeLayout. Bana bu geçici çözümü nasıl bulduğumu sorma !!!¯\_(ツ)_/¯

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

Tam örnek GitHub projesinde mevcuttur - https://github.com/amardeshbd/android-recycler-view-wrap-content

İşte düzeltmeyi eylem halinde gösteren bir demo ekran görüntüsü:

Ekran yayınlama


6
Teşekkürler adam .. onun yardımı çok .. ama çözüm sonra kaydırma zorlaşır böylece ben ayarlamak recyclerview.setNestedScrollingEnabled (yanlış); ve şimdi işi bir cazibe gibi.
Sagar Chavada

4
Bu yöntem geri dönüşüm görünümleri midir? geri dönüştürülecek yüzlerce nesnemiz varsa. Bu bir çözüm değil kesmek.
androidXP

1
Evet, @androidXP doğru, bu kesmek uzun bir liste için bir çözüm değil. Benim kullanım yeri, bu :-) onlardan biriydi, az 10'dan Ve diğer geçici çözümü nasıl bulduğunu gelince, rastgele şeyler denemeye oldu bir liste görünümünde öğeyi giderilmiştir
Hossain Khan

mükemmel. adnroid hatmi ve üst sorunumu çözdü. ;)
Amir Ziarati

2
Bu çözümü kullanırsanız, onBindView listedeki tüm öğeler için çağrılıyor, bu da recyclerview'in kullanıcı tabanı değil.
thedarkpassenger

54

Her ne kadar öneri

başka bir kaydırılabilir görünümün içine asla kaydırılabilir bir görünüm koymamalısınız

Sağlam bir tavsiye, ancak geri dönüşümcü görünümünde sabit bir yükseklik ayarlarsanız, iyi çalışmalıdır.

Bağdaştırıcı öğesi düzeninin yüksekliğini biliyorsanız, RecyclerView'ün yüksekliğini hesaplayabilirsiniz.

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

10
Herhangi bir fikri geri dönüştürmek için adaptorItemSize nasıl edinilir?
Krutik

1
Mucizevi şekilde çalışır! Küçük düzeltme olmalı: int viewHeight = adaptorItemSize * adaptorData.size (); recyclerView.getLayoutParams (). height = viewHeight;
Vaibhav Jani

3
AdaptorItemSize nasıl bulunur?
droidster.me

2
@JoakimEngstrom adapterItemSizeDeğişken nedir?
IgorGanapolsky

1
Kaydırma görünümünde geri dönüşüm görünümünden kaçının, çünkü kaydırma görünümü çocuğuna sonsuz alan sağlar. Bu, yükseklik olarak wrap_content değerine sahip geri dönüşümcü görünümünün dikey yönde (geri dönüşümcü görünümünün son öğesine kadar) sonsuz olarak ölçülmesine neden olur. Kaydırma görünümünde geri dönüşüm görünümü kullanmak yerine, yalnızca farklı öğe türlerine sahip geri dönüşüm görünümü kullanın. Bu uygulama ile, kaydırma görünümünün alt öğeleri görünüm türü gibi davranır. Bu görünüm türlerini geri dönüşümcü görünümünde kullanın.
abhishesh

28

RecyclerView için sabit yükseklik ayarının (benim gibi) birisi için işe yaramaması durumunda, sabit yükseklik çözümüne eklediğim şey şudur:

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
Gerçekten, bu benim için iyi çalıştı. Bu durumdayken, kaydırma görünümünü yukarı ve aşağı hareket ettirebildim ve kaydırma için geri dönüşüm görünümünü seçtiğimde, kaydırma görünümünden öncelikli olur.
Tavsiye

1
o da benim için çalıştı, sadece kaydırma görünümü doğrudan bir çocuk getParent kullandığınızdan emin olun
BigBen3216

Bu yöntem siyanojenmod dağılımları üzerinde de çalışır. Siyanojenmod üzerindeki sabit yükseklik çözümü çalışır, ancak yalnızca sabit yükseklik, listedeki tüm öğelerin mutlak yüksekliği ise, geri dönüşüm görünümünü ilk etapta kullanma noktasını tanımlar. Upvoted.
HappyKatz

Ayrıca recyclerView.setNestedScrollingEnabled (false);
Analizer


15

RecyclerViews, kaydırma yapmadığı sürece ScrollViews'e yerleştirilebilir. Bu durumda, sabit bir yükseklik yapmak mantıklıdır.

Uygun çözüm wrap_contentRecyclerView yüksekliğinde kullanmak ve daha sonra sargıyı düzgün bir şekilde işleyebilen özel bir LinearLayoutManager uygulamaktır.

Bu LinearLayoutManager'ı projenize kopyalayın: https://github.com/serso/android-linear-layout-manager/blob/master/lib/src/main/java/org/solovyev/android/views/llm/LinearLayoutManager.java

Ardından RecyclerView öğesini sarın:

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

Ve şu şekilde ayarlayın:

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

Düzenleme: Bu, RecyclerView ScrollView'ın dokunma olaylarını çalabildiğinden kaydırma ile ilgili sorunlara neden olabilir. Benim çözümüm, RecyclerView'i tamamen bırakmak ve bir LinearLayout'a gitmek, alt görünümleri programlı olarak şişirmek ve bunları mizanpaja eklemekti.


4
Geri dönüşüm görünümünde setNestedScrollingEnabled (false) öğesini arayamadınız mı?
Eshaan

14

Için ScrollView, aşağıdaki gibi kullanabilirsiniz fillViewport=trueve yapabilirsiniz layout_height="match_parent"ve içine geri dönüşüm görünümü koymak:

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

Kod üzerinden daha fazla yükseklik ayarlamasına gerek yoktur.


V23.2.1 kullanılarak iyi çalıştığı test edilmiştir. Geri dönüşüm görünümünün üstüne düzen eklemek için kullanıyordum.
winsontan520

sadece RecyclerView kaydırma ve ScrollView kaydırma değil
Samad

13

RecyclerViewYüksekliğini manuel olarak hesaplamak iyi değil, daha iyi bir özel kullanmaktır LayoutManager.

Yukarıdaki sorunu nedeni 's kaydırma olan herhangi bir görünümüdür ( ListView, GridView, RecyclerView) Başka bir görünümde bir çocuk olarak eklenti kaydırma sahip olduğunda' s yüksekliğini hesaplamak için başarısız oldu. Böylece onMeasureyöntemini geçersiz kılmak sorunu çözecektir.

Lütfen varsayılan düzen yöneticisini aşağıdakilerle değiştirin:

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

Verileri bağdaştırıcıya ayarladığımızda bu sınıfı nasıl arayabilirim?
Milan Gajera

11

Bunu dene. Çok geç cevap. Ama kesinlikle gelecekte herkese yardım et.

Scrollview'inizi NestedScrollView olarak ayarlayın

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

Geri Dönüşüm görünümünüzde

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

8
NestedScrollView içinde RecyclerView kullanımı, öğe görünmese bile listedeki her öğe için onBindView çağırıyor. Bu sorunun çözümü var mı?
thedarkpassenger

8

GÜNCELLEME: Yuvalanmış kaydırmayı destekleyen NestedScrollView ve RecyclerView gibi widget'lar olduğu için bu cevap şimdi tarihli.

başka bir kaydırılabilir görünümün içine asla kaydırılabilir bir görünüm koymamalısınız!

ana düzen geri dönüşüm görünümünüzü yapmanızı ve görünümlerinizi geri dönüşüm görünümünün öğeleri olarak koymanızı öneririm.

bu örneğe bir bakalım, geri dönüşüm cihazı adaptöründe birden çok görünümün nasıl kullanılacağını gösterir. örneğe bağlantı


birden fazla Recycler ile bir sayfa var, bu ikna için başka bir yolu var mı? daha fazla yorum tıkladığınızda daha fazla kayıt yükleyen instagram veya google play bölüm yorumu gibi bir şey
Ashkan

Görüntülemeyi ve görüşünüzü bu geri dönüşüm için ürün olarak görün
EC84B4

6
Bu saçmalık. RecyclerViews iç içe olabilir.
IgorGanapolsky

Bu cevap şimdi güncel değil. Yuvalanmış kaydırılabilir görünümlere izin veren NestedScrollView gibi şeylerimiz var. Yuvalanmış RecyclerViews şimdi de çalışıyor.
Corey Horn

7

RecyclerViewİçeri koyar NestedScrollViewve etkinleştirirseniz recyclerView.setNestedScrollingEnabled(false);, kaydırma iyi çalışır .
Ancak, bir sorun var

RecyclerView geri dönüşüm yapma

Örneğin, RecyclerView(içinde NestedScrollViewveya içinde ScrollView) 100 öğeniz var.
Ne zaman Activityfırlatma, 100 öğe yaratacak ( onCreateViewHolderve onBindViewHolder100 öğenin aynı anda denir olacaktır).
Örneğin, her öğe için API => etkinlik oluşturuldu -> 100 resim yüklenecek büyük bir resim yükleyeceksiniz.
Başlangıç ​​aktivitesini yavaşlatır ve geciktirir.
Olası çözüm :
- RecyclerViewÇoklu tip ile kullanmayı düşünmek .

Ancak, sizin durumunuzda, sadece birkaç öğe varsa RecyclerViewve geri dönüşüm varsa veya geri dönüşüm performansı çok fazla etkilemezse, basit için RecyclerViewiçeride kullanabilirsinizScrollView


ScollView içinde bile RecyclerView geri dönüşümünü nasıl yapabilirim? Teşekkürler!
Yalancı

2
@ Yalan, şu anda RecyclerViewkoymak sonra geri dönüşüm yapmak için bir yolu yoktur ScrollView. Geri dönüşüm istiyorsanız, başka bir yaklaşım düşünün (RecyclerView'ı birden çok türle kullanmak gibi)
Phan Van Linh

4

Bu şekilde aşağıdakilerden birini kullanabilirsiniz:

Bu satırı recyclerView xml görünümünüze ekleyin:

        android:nestedScrollingEnabled="false"

deneyin, recyclerview esnek yükseklik ile sorunsuz kaydırılacak

Umarım bu yardımcı olmuştur.


2

NestedScrollViewSorunu çözüyor gibi görünüyor . Bu düzeni kullanarak test ettim:

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

Ve sorunsuz çalışıyor


Dostum, Hala Aynı Sorun Var Sonra Scrollview NestedScrollview olarak değiştirildi.
MohanRaj S

mmm ... bazı kodları paylaşabilir misiniz ... Sıfır sorun yaşıyorum ama u bu tür sorunlarla asla bilemezsiniz
royB

kodumu e-posta veya yığın taşması yoluyla nasıl paylaşabilirim
MohanRaj S

2
bu kodu kullanmak, listede görünmeyen bile olsa listedeki tüm öğeler için onBindView öğesini çağırır. Bu, geri dönüşüm görüntülemesinin amacını yener.
thedarkpassenger

2

RecyclerView Scrolling'i devre dışı bırakmak için CustomLayoutManager kullandım. Ayrıca WrapContent olarak Recycler View kullanmayın, 0dp olarak kullanın, Ağırlık = 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();
    }
}

RecyclerView'de CustomLayoutManager kullanın:

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

Kullanıcı Arayüzü XML:

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

Aynı sorunu yaşıyordum. Ben denedim ve işe yarıyor. Ben xml ve java kodumu paylaşıyorum. Umarım bu birine yardımcı olur.

İşte 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 >

İşte ilgili java kodu. Mucizevi şekilde çalışır.

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

RecyclerView altındaki düzenler ne olacak?
Tapa

bu da işe yarıyor. Sadece kullanman gerek. NestedScrollViewkaydırma görünümü yerine
Zeeshan Shabbir

Evet, yalnızca NestedScrollView. Ama NestedScrollView + RecycleView ile çözüm RecyclerView çok yavaş nüfus çağrı (Ben RecyclerView sonra ilk görünüm Y-pozisyonunun hesaplanması için düşünüyorum)
Tapa Save


0

Aslında temel amacı RecyclerViewtelafi etmektir ListViewve ScrollView. Bunun yerine aslında ne yaptığını yapmanın a sahip RecyclerViewbir yer ScrollView, sadece bir sahip öneririz RecyclerViewçocukların birçok türde işleyebileceği.


1
Bu, yalnızca çocuklarınızın görüş alanı dışına kaydırılır kaydırılmaz toplanabilmeleri koşuluyla çalışır. Parça veya sokak görünümü olan çocuklarınız varsa, geri dönüşüm görünümüne her kaydırıldıklarında yeniden yüklemeye zorlandıkları için mantıklı değildir. Onları bir kaydırma görünümüne gömmek ve daha sonra alt kısımda bir geri dönüşüm görünümü oluşturmak daha mantıklıdır.
Simon

1
@Simon ViewHolder'da kullanışlı setIsRecyclable () var
ernazm

RecyclerView, ScrollView'in yerini alması amaçlanmayan ListView'in yerine geçer.
siroks

Bu yorum daha iyisini hak ediyor. Bu bir çözümdür ve kabul edilenden daha iyidir.
Kai Wang

0

Önce kullanmalısınız NestedScrollViewyerine ScrollViewve koyun RecyclerViewiçini NestedScrollView.

Ekranın yüksekliğini ve genişliğini ölçmek için Özel düzen sınıfını kullanın:

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

Ve aşağıdaki kodun faaliyet / fragmanında aşağıdaki kodu uygulayın 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, ScrollView içinde yalnızca bir satır gösteriyorsa. Sadece satırınızın yüksekliğini ayarlamanız gerekir android:layout_height="wrap_content".


0

ayrıca geri dönüşüm görünümünün sorunsuzca yuvarlanması için LinearLayoutManager'ı geçersiz kılabilirsiniz

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

0

Partiye geç kaldığım için üzgünüz, ancak bahsettiğiniz dava için mükemmel çalışan başka bir çözüm var gibi görünüyor.

Bir geri dönüşümcü görünümünde bir geri dönüşüm görünümü kullanıyorsanız, gayet iyi çalışıyor gibi görünüyor. Şahsen denedim ve kullandım ve hiç yavaşlık ve sarsıntı vermiyor gibi görünüyor. Şimdi bunun iyi bir uygulama olup olmadığından emin değilim, ancak çoklu geri dönüşüm görünümlerini iç içe yerleştirmek, iç içe kaydırma görünümü bile yavaşlar. Ama bu iyi çalışıyor gibi görünüyor. Lütfen bir deneyin. Eminim yuvalama bununla mükemmel olacak.



-2

** Benim için çalışan çözüm
wrap_content olarak yükseklikle NestedScrollView kullanın

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

// Satır içeriğiniz buraya geliyor


Benzer bir yanıttaki bazı yorumlar, iç içe kaydırmanın devre dışı bırakılmasının, RecyclerView kullanmanın amacını yendiğini, yani görünümleri geri dönüştürmeyeceğini söylüyor. Bunu nasıl doğrulayacağınızdan emin değilim.
jk7

1
NestedScrollingEnabled = "false" ayarı, RecyclerView uygulamasının en azından kurulumumda (NestedScrollView içindeki bir RecyclerView) görünümlerini geri dönüştürmemesine neden olur. RecyclerView öğesine bir RecyclerListener ekleyerek ve onViewRecycled () yönteminin içinde bir kesme noktası ayarlayarak onaylanır.
jk7
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.