RecyclerView внутри ScrollView не работает

Я пытаюсь реализовать макет, содержащий RecyclerView и ScrollView в том же макете.

Макет:

<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

Вещи, которые я пробовал:

  • вид карты внутри ScrollView (теперь ScrollView содержит RecyclerView) - может видеть карту до тех пор, пока RecyclerView
  • Первоначальная мысль заключалась в том, чтобы реализовать этот viewGroup с помощью RecyclerView вместо ScrollView, где один из них рассматривает тип CardView, но я получил те же результаты, что и с ScrollView

Ответ 2

Я знаю, что опаздываю в игре, но проблема все еще существует даже после того, как Google android.support.v7.widget.RecyclerView

Проблема, которую я получаю сейчас, - это RecyclerView с layout_height=wrap_content не layout_height=wrap_content высоту всех проблем с элементами внутри ScrollView, ScrollView только в ScrollView Marshmallow и Nougat+ (API 23, 24, 25).
(ОБНОВЛЕНИЕ: Замена ScrollView на android.support.v4.widget.NestedScrollView работает на всех версиях. Я почему-то пропустил тестирование принятого решения. Добавил это в свой проект на github в качестве демонстрационного примера.)

Попробовав разные вещи, я нашел обходной путь, который решает эту проблему.

Вот моя структура макета в двух словах:

<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

Вот демонстрационный скриншот, показывающий исправление в действии:

Screencast

Ответ 3

Хотя рекомендация, что

вы не должны ставить прокручиваемое представление внутри другого прокручиваемого представления

Является советом по звуку, однако, если вы установите фиксированную высоту на просмотр ресайклера, он должен работать нормально.

Если вы знаете высоту макета элемента адаптера, вы можете просто вычислить высоту RecyclerView.

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

Ответ 4

Если установка фиксированной высоты для 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) {

    }
});

Ответ 5

Новая библиотека поддержки Android 23.2 решает эту проблему, теперь вы можете установить wrap_content в качестве высоты вашего RecyclerView и работать правильно.

Библиотека поддержки Android 23.2

Ответ 6

RecyclerViews прекрасно вставляются в ScrollViews, пока они не прокручиваются. В этом случае имеет смысл сделать его фиксированной высотой.

Правильное решение - использовать wrap_content на высоте RecyclerView, а затем реализовать пользовательский LinearLayoutManager, который может правильно обрабатывать упаковку.

Скопируйте этот LinearLayoutManager в свой проект: https://github.com/serso/android-linear-layout-manager/blob/master/lib/src/main/java/org/solovyev/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 может украсть события касания ScrollView. Мое решение состояло в том, чтобы полностью перехватить RecyclerView и перейти с LinearLayout, программно раздуть subviews и добавить их в макет.

Ответ 7

Для ScrollView вы можете использовать fillViewport=true и сделать layout_height="match_parent", как показано ниже, и поместить вид recycler внутри:

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

Никакой дополнительной регулировки высоты не требуется с помощью кода.

Ответ 8

Вычисление высоты 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 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 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 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 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");
    }
}
}

Ответ 9

Попробуйте это. Очень поздний ответ. Но, безусловно, помогите кому-нибудь в будущем.

Установите Scrollview в 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);

Ответ 10

UPDATE: этот ответ уже устарел, поскольку существуют такие виджеты, как NestedScrollView и RecyclerView, которые поддерживают вложенную прокрутку.

вы никогда не должны ставить прокручиваемое представление внутри другого прокручиваемого вида!

Я предлагаю вам сделать ваш основной вид ресайклера макета и поместить ваши представления в качестве элементов просмотра recycler.

взгляните на этот пример, он показывает, как использовать несколько видов в адаптере просмотра recycler. ссылка на пример

Ответ 11

Если вы поместите RecyclerView в NestedScrollView и включите recyclerView.setNestedScrollingEnabled(false); Прокрутка будет работать хорошо.
Тем не менее, есть проблема

RecyclerView не перерабатывать

Например, ваш RecyclerView (внутри NestedScrollView или ScrollView) имеет 100 элементов.
При запуске Activity будет onCreateViewHolder onBindViewHolder 100 (onCreateViewHolder и onBindViewHolder из 100 элементов будут вызваны одновременно).
Например, для каждого элемента вы загрузите большое изображение из API => действие создано → 100 изображений будет загружено.
Это делает медленную стартовую активность и отставание.
Возможное решение:
- Думая об использовании RecyclerView с несколькими типами.

Однако, если в вашем случае в RecyclerView есть только несколько элементов, и их повторное использование или отсутствие повторного использования не сильно влияет на производительность, вы можете использовать RecyclerView внутри ScrollView для простого

Ответ 12

Вы можете использовать этот способ:

Добавьте эту строку в свой вид recyclerView xml:

        android:nestedScrollingEnabled="false"

попробуйте, recyclerview будет плавно прокручиваться с гибкой высотой

надеюсь, что это помогло.

Ответ 13

Кажется, что 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>

И он работает без проблем

Ответ 14

У меня была такая же проблема. Это то, что я пробовал, и он работает. Я использую свой xml и java-код. Надеюсь, это поможет кому-то.

Вот xml

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

  

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

Вот связанный Java-код. Он работает как шарм.

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

Ответ 15

Это делает трюк:

recyclerView.setNestedScrollingEnabled(false);

Ответ 16

На самом деле основной целью RecyclerView является компенсация ListView и ScrollView. Вместо того, чтобы делать то, что вы на самом деле делаете: имея RecyclerView в ScrollView, я предлагаю иметь только RecyclerView, который может обрабатывать многие типы детей.

Ответ 17

Сначала вы должны использовать 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!");
            }
        }
    });

Ответ 18

Если RecyclerView показывает только одну строку внутри ScrollView. Вам просто нужно установить высоту строки в android:layout_height="wrap_content".

Ответ 19

вы также можете переопределить LinearLayoutManager, чтобы плагин recyclerview плавно

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

Ответ 20

Извините, что опаздывает на вечеринку, но похоже, что есть еще одно решение, которое отлично подходит для случая, о котором вы упомянули.

Если вы используете просмотр recycler внутри вида ресайклера, он работает отлично. Я лично пробовал и использовал его, и, похоже, он не медлил и не вялость. Теперь я не уверен, что это хорошая практика или нет, но вложенные множественные просмотры recycler, даже вложенный просмотр прокрутки замедляется. Но это, похоже, работает хорошо. Пожалуйста, попробуйте. Я уверен, что вложение будет прекрасно в этом.

Ответ 21

Я использовал CustomLayoutManager, чтобы отключить прокрутку RecyclerView. Также не используйте Recycler View в качестве WrapContent, используйте его как 0dp, Weight = 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();
    }
}

Используйте CustomLayoutManager в RecyclerView:

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

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

Ответ 22

Вот мое рабочее решение: для RecyclerView лучше вычислить высоту контента и установить фиксированную высоту.

    <ScrollView
        android:id="@+id/main_scroll_container"
        android:fillViewport="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="wrap_content">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/product_results_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:persistentDrawingCache="none"
                android:alwaysDrawnWithCache="false"
                android:scrollbars="vertical"/>
         </LinearLayout>
    </ScrollView>

Ответ 23

** Решение, которое сработало для меня
Используйте NestedScrollView с высотой в качестве wrap_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"

//Содержимое вашей строки идет здесь