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

Как использовать 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>
4b9b3361

Ответ 1

Замените 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

Ответ 2

ОБНОВЛЕНИЕ 1

Начиная с библиотеки поддержки Android 23.2.0 для LayoutManager добавлен метод setAutoMeasureEnabled(true). Это делает 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 -based, создайте для него аналог Adapter. и заставить его вести себя как ListView или RecyclerView

Ответ 3

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

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

3) recyclerView.setNestedScrollingEnabled(false)

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

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

Ответ 4

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

Ответ 5

Просто добавив 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>

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

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

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

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

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

Ответ 11

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

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

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

Ответ 12

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

Ответ 13

Если вы используете 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); выполнит трюк.

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

Ответ 14

Мне пришлось реализовать 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>

Ответ 15

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

Ответ 16

Есть много хороших ответов. Ключ в том, что вы должны установить для 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" />

Ответ 17

Для 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>

Ответ 18

Если вы используете RecyclerView ScrollListener внутри NestedScrollView, слушатель addOnScrollListener не работает должным образом, если вы используете оба.

Используйте этот код.

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState); 
              ......
        }
    });

этот код работает нормально RecyclerView ScrollListener внутри NestedScrollView.

Спасибо

Ответ 19

не используйте recyclerView внутри NestedScrollView. это может вызвать каскадные проблемы! Я предлагаю использовать ItemViewTypes в RecyclerView для обработки нескольких видов представлений. просто добавьте RecyclerView с шириной и высотой match_parent. затем в вашем recyclerViewAdapter переопределите getItemViewType и используйте позицию для обработки того, какой макет нужно надуть. после этого вы можете обрабатывать свой видовой держатель с помощью метода onBindViewHolder.

Ответ 20

nestedScrollView.setNestedScrollingEnabled(true);

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


<androidx.core.widget.NestedScrollView
    android:id="@+id/nested"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:layout_below="@id/appBarLayout_orders"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"> 

    <androidx.constraintlayout.widget.ConstraintLayout ...

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

Ответ 21

RecyclerView с NestedScrollView

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