it-roy-ru.com

Как использовать RecyclerView внутри NestedScrollView?

Как использовать RecyclerView внутри переменной NestedScrollView? RecyclerView после настройки адаптера не отображается.

UPDATEОбновлен код макета.

<Android.support.v4.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:padding="@dimen/keyline_1">

    </RelativeLayout>

    <View
        Android:id="@+id/separator"
        Android:layout_width="match_parent"
        Android:layout_height="1dp"
        Android:background="#e5e5e5" />

    <Android.support.v7.widget.RecyclerView
        Android:id="@+id/conversation"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" />

</LinearLayout>

</Android.support.v4.widget.NestedScrollView>
166
Mecid

Замените свой recyclerView на, 

<Android.support.v7.widget.RecyclerView
    Android:id="@+id/conversation"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content" />

вот, 

app:layout_behavior="@string/appbar_scrolling_view_behavior"

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

Еще одна вещь, нет необходимости помещать свой RecyclerView внутри NestedScrollView

177
Rahul Upadhyay

ОБНОВЛЕНИЕ 1

Начиная с библиотеки поддержки Android 23.2.0 был добавлен метод setAutoMeasureEnabled(true) для LayoutManager. Это делает RecyclerView, чтобы обернуть его содержимое и работает как шарм.
http://Android-developers.blogspot.ru/2016/02/Android-support-library-232.html

Так что просто добавьте что-то вроде этого:

    LayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setAutoMeasureEnabled(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setNestedScrollingEnabled(false);


ОБНОВЛЕНИЕ 2

Поскольку 27.1.0 setAutoMeasureEnabled устарела, вы должны предоставить пользовательскую реализацию LayoutManager с переопределенным методом isAutoMeasureEnabled()

Но после многих случаев использования RecyclerView я настоятельно рекомендую не использовать его в режим обтекания, потому что это не то, для чего он предназначен. Попробуйте провести рефакторинг всего макета, используя обычный RecyclerView с несколькими типами элементов. Или используйте подход с LinearLayout, который я описал ниже как последнее средство


Старый ответ (не рекомендуется)

Вы можете использовать RecyclerView внутри NestedScrollView. Прежде всего вы должны реализовать свой собственный LinearLayoutManager, он делает ваш RecyclerView обернуть его содержимое. Например:

public class WrappingLinearLayoutManager extends LinearLayoutManager
{

    public WrappingLinearLayoutManager(Context context) {
        super(context);
    }

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

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

    @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(0, View.MeasureSpec.UNSPECIFIED),
                        heightSpec,
                        mMeasuredDimension);

                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                measureScrapChild(recycler, i,
                        widthSpec,
                        View.MeasureSpec.makeMeasureSpec(0, 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);
        if (view.getVisibility() == View.GONE) {
            measuredDimension[0] = 0;
            measuredDimension[1] = 0;
            return;
        }
        // For adding Item Decor Insets to view
        super.measureChildWithMargins(view, 0, 0);
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(
                widthSpec,
                getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
                p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(
                heightSpec,
                getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
                p.height);
        view.measure(childWidthSpec, childHeightSpec);

        // Get decorated measurements
        measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
        measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
        recycler.recycleView(view);
    }
}

После этого используйте этот LayoutManager для своего RecyclerView

recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));

Но вы также должны вызвать эти два метода:

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

Здесь setNestedScrollingEnabled(false) отключает прокрутку для RecyclerView, чтобы он не перехватывал событие прокрутки из NestedScrollView. И setHasFixedSize(false) определяет, что изменения в содержимом адаптера могут изменить размер RecyclerView

Важное примечание: В некоторых случаях это решение немного глючит и имеет проблемы с производительностью, поэтому, если у вас много элементов в RecyclerView, я бы порекомендовал использовать пользовательскую реализацию представления списка на основе LinearLayout, создайте аналог Адаптер для него и заставить его вести себя как ListView или RecyclerView

110
smbd uknow

1) Вы должны использовать библиотеку поддержки 23.2.0 (или) выше 

2) и RecyclerView высота будет wrap_content

3) recyclerView.setNestedScrollingEnabled(false)

Но при этом шаблон утилизатора не работает. (т.е. все представления будут загружены одновременно, потому что wrap_content нужна высота завершения RecyclerView, поэтому он будет рисовать все дочерние View одновременно. Ни одно представление не будет переработано). Старайтесь не использовать этот шаблон утилитой, если это действительно не требуется. Попробуйте использовать viewType и добавьте все другие представления, которые необходимо прокрутить до RecyclerView, вместо использования RecyclerView в Scrollview. Влияние на производительность будет очень высоким.

Чтобы сделать это простым, «он просто действует как LinearLayout со всеми дочерними представлениями»

84
Ashok Varma

Вы можете использовать Android:fillViewport="true", чтобы NestedScrollView измерить RecyclerView. RecyclerView заполнит оставшуюся высоту. поэтому, если вы хотите прокрутить NestScrollView, вы можете установить RecyclerView's minHeight.

33
zayn

Простое добавление recyclerView.setNestedScrollingEnabled(false); до того, как setAdapter само по себе сработало для меня. Я нигде не добавил app:layout_behavior="@string/appbar_scrolling_view_behavior" и не установил никакого собственного менеджера макета

<Android.support.v4.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:background="@color/white"
        Android:orientation="vertical">

        <LinearLayout
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:layout_marginLeft="15dp"
            Android:layout_marginRight="15dp"
            Android:orientation="vertical">

            <TextView
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:textColor="@color/white"
                Android:text="Some Text..."
                Android:padding="15dp" />

        </LinearLayout>

        <LinearLayout
            Android:orientation="vertical"
            Android:padding="15dp"
            Android:layout_marginTop="10dp"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content">

            <TextView
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:text="Quick Links"
                Android:textColor="@color/black"
                Android:textStyle="bold"
                Android:textAllCaps="true"
                Android:paddingLeft="20dp"
                Android:drawableLeft="@drawable/ic_trending_up_black_24dp"
                Android:drawablePadding="10dp"
                Android:layout_marginBottom="10dp"
                Android:textSize="16sp"/>

            <View
                Android:layout_width="fill_parent"
                Android:layout_height="1dp"
                Android:background="#efefef"/>

            <Android.support.v7.widget.RecyclerView xmlns:Android="http://schemas.Android.com/apk/res/Android"
                Android:id="@+id/recyclerview"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent" />
        </LinearLayout>

    </LinearLayout>

</Android.support.v4.widget.NestedScrollView>
25
Vignesh Sundar

Это то, что работает для меня

<Android.support.v4.widget.NestedScrollView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <Android.support.v7.widget.RecyclerView
        Android:id="@+id/rv_recycler_view"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</Android.support.v4.widget.NestedScrollView>
19
Ness Tyagi

Попробуйте использовать эту библиотеку - https://github.com/serso/Android-linear-layout-manager .

LayoutManager из библиотеки заставляет RecyclerView обернуть его содержимое. В этом случае RecyclerView будет "таким же большим, как внутренние виды", поэтому у него не будет полос прокрутки, и пользователь будет использовать возможности прокрутки NestedScrollView. Следовательно, он не будет неоднозначным, как «прокручиваемый внутри прокручиваемый».

7
alcsan

Существует простой и тестовый код, который вы можете проверить

<Android.support.v4.widget.NestedScrollView
     Android:layout_width="match_parent"
     Android:layout_height="match_parent"
     Android:fillViewport="true"
     app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <Android.support.v7.widget.RecyclerView
           Android:layout_width="match_parent"
           Android:layout_height="match_parent"/>
   </Android.support.v4.widget.NestedScrollView>
7
Hakim Khan

Я использовал RecyclerView внутри NestedScrollView, и это сработало для меня. Единственное, о чем я должен был помнить, это то, что NestedScrollView принимает только одно дочернее представление. Так что в моем случае я использовал видовую группу LienearLayout, в которой находился мой RecyclerView, а также ряд других нужных мне видов.

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

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

Поэтому, чтобы решить эту проблему, мне пришлось отключить функцию прокрутки моего RecyclerView с помощью этого метода movieListNewRecyclerView.setNestedScrollingEnabled(false);

Вы можете проверить мой Instagram для короткого видео о том, что я на самом деле сделал. Это моя ручка instagram ofelix03

Нажмите на это изображение, чтобы увидеть, что я сделал

6
Felix Otoo

Вот код, который я использую, чтобы избежать проблем с прокруткой:

mRecyclerView = (RecyclerView) view.findViewById(Android.R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
6
Anton Tananaev

У меня есть Viewpager и RecyclerView внутри NestedScrollView. После добавления строк ниже

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

Я решил проблему медленной прокрутки и задержки прокрутки.

4
Isham

Если вы используете RecyclerView-23.2.1 или позже. Следующее решение будет работать нормально: 

В свой макет добавить RecyclerView, как это:

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

И в вашем файле Java:

RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());
layoutManager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(new YourListAdapter(getContext()));

Здесь layoutManager.setAutoMeasureEnabled(true); сделает свое дело. 

Проверьте эту проблему и этот блог разработчика для получения дополнительной информации.

3
abhilvare

Вы не можете использовать представление рециркулятора во вложенном представлении прокрутки. Он не предназначен для того, чтобы содержать дополнительные прокручиваемые представления, но потому, что он является дочерним по отношению к самому макету с прокруткой, вам необходим вложенный прокручиваемый вид. У меня возникла та же проблема, но в итоге я переместил свое текстовое представление в представление заголовка в представлении реселлера, сделало его рекурсором прямым потомком макета координатора и удалило вложенное представление прокрутки. Тогда все мои проблемы исчезли.

3
Barry Irvine

Есть много хороших ответов. Ключ в том, что вы должны установить nestedScrollingEnabled в false. Как уже упоминалось выше, вы можете сделать это в коде Java:

mRecyclerView.setNestedScrollingEnabled(false);

Но также у вас есть возможность установить то же свойство в коде xml (Android:nestedScrollingEnabled="false"):

 <Android.support.v7.widget.RecyclerView
 Android:id="@+id/recyclerview"
 Android:nestedScrollingEnabled="false"
 Android:layout_width="match_parent"
 Android:layout_height="match_parent" />
1
Alex Misulya

Для androidx он называется androidx.core.widget.NestedScrollView - и он также прокручивает похожее масло со свойствами isScrollContainer и measureAllChildren:

<!-- Scrolling Content -->
<androidx.core.widget.NestedScrollView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:isScrollContainer="true"
    Android:measureAllChildren="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <androidx.recyclerview.widget.RecyclerView
        Android:id="@+id/recyclerview"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:fastScrollEnabled="true"
        Android:scrollbarStyle="insideInset"
        Android:scrollbars="vertical"
        Android:splitMotionEvents="false"
        Android:verticalScrollbarPosition="right"/>

</androidx.core.widget.NestedScrollView>
1
Martin Zeitler

Мне пришлось реализовать CoordinatorLayout с прокруткой на панели инструментов, и мне просто пришлось целый день возиться с этим. У меня это работает, удалив NestedScrollView на всех. Так что я просто использую RelativeLayout в корне.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/rv_nearby"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</RelativeLayout>
1
Bogdan Ustyak

Одним из решений, позволяющих сохранить функцию рециркуляции в обзоре утилизатора и избежать его повторной загрузки для загрузки всех ваших данных, является установка фиксированной высоты в самом обзоре утилизатора. Таким образом, просмотр реселлера ограничивается только загрузкой настолько, насколько его высота может показать пользователь, тем самым перерабатывая его элемент, если вы когда-нибудь прокрутите его вниз/вверх.

0
BradlyMan