如何在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>

当前回答

我在NestedScrollView内使用RecyclerView,它为我工作。我必须记住的唯一问题是NestedScrollView只接受一个子视图。所以在我的情况下,我使用的LienearLayout视图组,它是住房我的RecyclerView加上其他一些我需要的视图。

我经历了一个问题,把我的RecyclerView内的NestedScrollView。我意识到我的RecyclerView的内容滚动变慢了。

我后来意识到我的RecyclerView正在接收滚动事件,因此与NestedScrollView的滚动行为相冲突。

所以为了解决这个问题,我不得不禁用我的RecyclerView的滚动功能与这个方法movieListNewRecyclerView.setNestedScrollingEnabled(false);

你可以在我的Instagram上查看我实际做了什么。这是我的instagram账号elix03

其他回答

如果您使用的是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(真正的);会成功的。

查看这个问题和这个开发者博客以获得更多信息。

有很多很好的答案。关键是你必须将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" />

简单地添加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>

更新1

自Android支持库23.2.0以来,为布局管理器添加了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与几个项目类型重构整个布局。或者使用线性布局的方法,我在下面描述作为最后的手段

旧答案(不推荐)

你可以在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);
    }
}

之后,使用这个LayoutManager为您的RecyclerView

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

但你也应该调用这两个方法:

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

这里setNestedScrollingEnabled(false)禁用了RecyclerView的滚动,因此它不会从NestedScrollView中拦截滚动事件。setHasFixedSize(false)确定适配器内容的变化可以改变RecyclerView的大小

重要提示:这个解决方案是小bug在某些情况下,有问题与性能,所以如果你有很多项目在你的RecyclerView,我建议使用自定义线性布局的实现列表视图,为它创建类似的适配器,使其行为像ListView或RecyclerView

如果你在NestedScrollView中使用RecyclerView ScrollListener, addOnScrollListener监听器不能正常工作。

使用这段代码。

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

这段代码工作良好的RecyclerView ScrollListener内的NestedScrollView。

谢谢