处理RecyclerView、NestedScrollView和CardView

7
我将在我的应用程序中实现这个UI: UI 之前我试过一些方法: 1. 使用CollapsingToolbarLayout 我将我的CardView放入CollapsingToolbarLayout中,然后将它们全部放在AppBarLayout中。
<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed" >

            <CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
                  <!-- My Views Goes there -->
            </CardView

            <android.support.v7.widget.Toolbar
                android:id="@+id/flexible.example.toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@null"
                app:layout_collapseMode="pin"
                style="@style/ToolBarWithNavigationBack"
                />
        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <RecyclerView
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
    ></RecyclerView>

</android.support.design.widget.CoordinatorLayout>

P.S: 我已删除无关代码,请勿提及我

这种方法是正确的,但是当CardView高度超过屏幕高度时,它的内容被AppBarLayout忽略,用户无法看到。

2. 使用NestedScrollView 我将CardViewRecyclerView放在NestedScrollView中。但问题是,当用户滚动到RecyclerView底部,然后向上滚动时,滑动会变得卡顿和错误,并且停止在某个位置,用户必须不断滚动才能回到顶部!

<android.support.v4.widget.NestedScrollView
    android:id="@+id/nested_scrollbar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="fill_vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:scrollbars="none" >
        <LinearLayout
            android:id="@+id/nested_scrollbar_linear"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

                <android.support.v7.widget.CardView
                    android:id="@+id/flexible.example.cardview"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:cardBackgroundColor="@color/post_card_backgroind"
                    app:cardCornerRadius="0dp"
                    app:cardElevation="0dp">

                </android.support.v7.widget.CardView>

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/list_view"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="@dimen/four"
                    android:layout_marginEnd="@dimen/four"
                    android:layout_marginLeft="@dimen/four"
                    android:layout_marginRight="@dimen/four"
                    android:layout_marginStart="@dimen/four"
                    android:layout_marginTop="@dimen/four"
                    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

如何解决这个问题?!我不想使用为recyclerview创建头的适配器,因为其中一些会导致性能问题。

答案

RecyclerView放在NestedScrollView中,如2所示,并应用.setNestedScrollingEnabled并将其设置为false


1
如果暂时忽略性能问题,您想要将CardView固定在顶部还是像RecyclerView中的其他项一样简单滚动? - Rehan
@Rehan 是的,我想要完全这样。 - MAY3AM
我实际上问你想要哪一个。假设你想要第二个(即CardViewRecyclerView中的其他项一样滚动)。你能发布第二个布局,其中你将CardViewRecyclerView放在NestedScrollView中吗? - Rehan
@Rehan 哎呀!我的错,抱歉。我想要的是这个:这是一个帖子活动,CardView 包含帖子相关信息(如图像、描述等),在它下面的 RecyclerView 中,我们将展示相关帖子。我希望当用户滚动 RecyclerView 时,CardView 也会滚动并离开屏幕。 - MAY3AM
2个回答

10

您应该使用getItemViewType。它很容易使用,不会产生任何性能开销。将您的Adapter代码更改为以下内容:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    class CardViewHolder extends RecyclerView.ViewHolder {
        ...
    }

    class ItemViewHolder extends RecyclerView.ViewHolder {
        ...
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return 0; // Card Type
        } else {
            return 1; // Item Type
        };
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case 0: 
                 // Card Type
                 return new CardViewHolder(...);
             case 1: 
                 // Item Type
                 return new ItemViewHolder(...);
         }
    }

    // Optional
    // If your data list does not contain CardView data
    // You may need to add extra count in adapter

    @Override
    public final int getItemCount() {
        // Add one count for CardView data
        return list.size() + 1;
    }

    @Override
    public T getItem(int position) {
        // As the position is change because of CardView at position 0
        // So you may have to decrement the corresponding index 
        return list.get(position - 1);
    }
}

更新1

如果您不想更新适配器,您可以使用

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
              <!-- Views Goes there -->
        </CardView>
        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            // This is the key
            android:nestedScrollingEnabled="false"/>
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

android:nestedScrollingEnabled可以通过xml在API Level 21及以上版本中使用。对于较低的API,请使用Java方法,即recyclerView.setNestedScrollingEnabled(false);ViewCompat.setNestedScrollingEnabled(recyclerView, false);

注意(2016年12月12日)

在使用嵌套滚动时,请注意RecyclerView未回收视图的已知问题,如此处此处所述(由Arpit Ratan分别回答了明显的原因)。因此,我建议采用第一种解决方案,即使用getItemViewType。有关更多详细信息,请参见完整且更好的答案,例如这个这个


更新2

您可以使用setFullSpan。如果您的StaggeredGridLayoutManager的方向是垂直的,则可以使用以下代码将其宽度跨越整个屏幕:

public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    if (position == 0) {
        StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
        layoutParams.setFullSpan(true);
    }
}

@MAY3AM 是的,你需要设置 LayoutParams 来使第一个视图全屏(正如我在 更新2 中提到的)。但是如果你不想这样做,仍然可以使用 NestedScrollView(就像在 更新1 中一样)。它应该适用于你! - Rehan
正如我在问题中所说的,我们尝试了两种方法。让我们谈谈NestedScrollView,它是可靠的,但当用户滚动到RecyclerView的底部并向上滚动时,fling会变得不稳定和卡顿!你有什么解决方案? - MAY3AM
@MAY3AM 是的,可能是行为问题。尝试在NestedScrollViewCardViewRecyclerView中添加app:layout_behavior="@string/appbar_scrolling_view_behavior"。也许可以帮助你。 - Rehan
@MAY3AM 此外,尝试在RecyclerView中将android:nestedScrollingEnabled设置为true - Rehan
1
嘿,老铁!“ nestedScrollingEnabled ”就是答案!我已经在我的代码中将其设置为RecyclerView了:ViewCompat.setNestedScrollingEnabled(recyclerView, false)。把它发布为答案,我会接受的。非常感谢 ;) - MAY3AM
显示剩余6条评论

4

2.使用中的问题

但问题是,当用户滑动到RecyclerView的底部,然后向上滑动时

可以在NestedScrollView下的第一个布局中添加android:descendantFocusability="blocksDescendants"来处理此问题,如下所示:

<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scrollbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:scrollbars="none" >
    <LinearLayout
        android:id="@+id/nested_scrollbar_linear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:descendantFocusability="blocksDescendants" >

这对我很有用。NestedScrollView在Recyclerview重新调整大小时滚动到顶部


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接