Android 如何在NestedScrollView中使用RecyclerView?

Android 如何在NestedScrollView中使用RecyclerView?,android,android-recyclerview,Android,Android Recyclerview,如何在NestedScrollView内部使用RecyclerView? 设置适配器后,RecyclerView内容不可见 更新布局代码已更新 <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

如何在
NestedScrollView
内部使用
RecyclerView
? 设置适配器后,
RecyclerView
内容不可见

更新布局代码已更新

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


您可以使用
android:fillViewport=“true”
制作
NestedScrollView
测量
RecyclerView
RecyclerView
将填充剩余高度。因此,如果你想滚动
nestcrollview
,你可以设置
RecyclerView
minHeight

,你可以使用
android:fillViewport=“true”
使
NestedScrollView
测量
RecyclerView
RecyclerView
将填充剩余高度。因此,如果要滚动
嵌套滚动视图
,可以设置
回收器视图
最小高度

,不能在嵌套滚动视图中使用回收器视图。它并不打算包含更多的可滚动视图,但因为它是滚动布局本身的子级,所以您需要嵌套的滚动视图。我也遇到了同样的问题,但最后我将我的textview移动到了recyclerview中的headerview,使recyclerview成为coordinator布局的直接子视图,并删除了嵌套的滚动视图。然后我所有的问题都消失了。

您不能在嵌套的滚动视图中使用回收器视图。它并不打算包含更多的可滚动视图,但因为它是滚动布局本身的子级,所以您需要嵌套的滚动视图。我也遇到了同样的问题,但最后我将我的textview移动到了recyclerview中的headerview,使recyclerview成为coordinator布局的直接子视图,并删除了嵌套的滚动视图。然后我所有的问题都消失了。

<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" />
我会处理剩下的事情


还有一件事,无需将您的recyclerView放入NestedScrollView中

将您的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" />
我会处理剩下的事情


还有一件事,无需将您的recyclerView放入NestedScrollView中

更新1

自从Android支持库23.2.0以来,为LayoutManager添加了方法
setAutoMeasureEnabled(true)
。它使RecyclerView能够包装其内容,并像一个符咒一样工作。

因此,只需添加如下内容:

    LayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setAutoMeasureEnabled(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setNestedScrollingEnabled(false);
<android.support.v7.widget.RecyclerView
        android:id="@+id/review_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />

更新2

由于27.1.0
setAutoMeasureEnabled
已被弃用,因此您应该使用重写的方法
isAutoMeasureEnabled()

但是在多次使用RecyclerView之后,我强烈建议不要在包装模式下使用它,因为这不是它的目的。尝试使用带有多个项目类型的普通single RecyclerView重构整个布局。或者使用我在下面描述的线性布局方法作为最后手段


旧答案(不推荐)

您可以在
NestedScrollView
内部使用
RecyclerView
。 首先,您应该实现自己的自定义
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);
    }
}
但您也应该调用这两种方法:

recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
此处
setNestedScrollingEnabled(false)
RecyclerView
禁用滚动,因此它不会从
NestedScrollView
截取滚动事件。和
setHasFixedSize(false)
确定适配器内容的更改可以更改
RecyclerView的大小

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

重要提示:此解决方案在某些情况下存在小错误,并且性能有问题,因此如果您的
回收视图中有很多项,我建议使用基于自定义
线性布局的列表视图实现,为其创建适配器的模拟,并使其行为类似于
列表视图
回收视图
更新1

recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
自从Android支持库23.2.0以来,为LayoutManager添加了方法
setAutoMeasureEnabled(true)
。它使RecyclerView能够包装其内容,并像一个符咒一样工作。

因此,只需添加如下内容:

    LayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setAutoMeasureEnabled(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setNestedScrollingEnabled(false);
<android.support.v7.widget.RecyclerView
        android:id="@+id/review_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />

更新2

由于27.1.0
setAutoMeasureEnabled
已被弃用,因此您应该使用重写的方法
isAutoMeasureEnabled()

但是在多次使用RecyclerView之后,我强烈建议不要在包装模式下使用它,因为这不是它的目的。尝试使用带有多个项目类型的普通single RecyclerView重构整个布局。或者使用我在下面描述的线性布局方法作为最后手段


旧答案(不推荐)

您可以在
NestedScrollView
内部使用
RecyclerView
。 首先,您应该实现自己的自定义
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);
    }
}
但您也应该调用这两种方法:

recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
此处
setNestedScrollingEnabled(false)
RecyclerView
禁用滚动,因此它不会从
NestedScrollView
截取滚动事件。和
setHasFixedSize(false)
确定适配器内容的更改可以更改
RecyclerView的大小

recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
重要提示:此解决方案在某些情况下存在小错误,并且性能有问题,因此如果您的
回收视图中有很多项,我建议使用基于自定义
线性布局的列表视图实现,为它创建适配器的模拟,并使其行为类似于
列表视图
回收视图
尝试使用此库-

recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
库的LayoutManager使RecyclerView包装其内容。在这种情况下,我们
    <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" />
mRecyclerView.setNestedScrollingEnabled(false);
 <android.support.v7.widget.RecyclerView
 android:id="@+id/recyclerview"
 android:nestedScrollingEnabled="false"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />
<!-- 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>
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState); 
              ......
        }
    });
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"/>
 <com.your_package.utils.NestedRecyclerView
      android:id="@+id/rv_test"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
<androidx.core.widget.NestedScrollView 
  android:id="@+id/nestedScrollView" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent">

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

    <androidx.recyclerview.widget.RecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:nestedScrollingEnabled="false" />

  </LinearLayout>
</androidx.core.widget.NestedScrollView>