Android 内置RecyclerView的可滚动CardView

Android 内置RecyclerView的可滚动CardView,android,android-recyclerview,scrollview,cardview,Android,Android Recyclerview,Scrollview,Cardview,我想实现一个屏幕,其中我有一个包含RecyclerView的卡片视图 CardView应该与RecyclerView的内容具有相同的高度,这意味着如果RecyclerView只有很少的项目,我应该看到卡片的底角和底部阴影,但是如果RecyclerView有很多项目,卡片视图应该“滚动”在RecyclerView中,cardview的底角和阴影位于RecyclerView的底部 下面是RecyclerView位于顶部时的外观: 当用户开始滚动时,随着RecyclerView滚动,上角消失: 最

我想实现一个屏幕,其中我有一个包含RecyclerView的卡片视图

CardView应该与RecyclerView的内容具有相同的高度,这意味着如果RecyclerView只有很少的项目,我应该看到卡片的底角和底部阴影,但是如果RecyclerView有很多项目,卡片视图应该“滚动”在RecyclerView中,cardview的底角和阴影位于RecyclerView的底部

下面是RecyclerView位于顶部时的外观:

当用户开始滚动时,随着RecyclerView滚动,上角消失:

最后,当用户到达RecyclerView的底部时,CardView的底角和阴影会出现:

从现在起,我设法通过将RecyclerView放在CardView中,将CardView放在NestedScrollView中实现了一个正常工作的实现,但这打破了fling手势

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:clipChildren="false"
    android:id="@+id/containerLayout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    tools:ignore="MissingPrefix">

    <android.support.v4.widget.NestedScrollView
        android:clipToPadding="false"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:paddingBottom="16dp"
        android:paddingLeft="85dp"
        android:paddingRight="85dp"
        android:paddingTop="16dp">

        <android.support.v7.widget.CardView
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            app:cardBackgroundColor="?android:attr/windowBackground">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"/>
        </android.support.v7.widget.CardView>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

你对我如何实现这样的设计有什么提示或想法吗?我想协调人的安排可以帮我,但我找不到任何东西


谢谢你

我有一个基于我以前使用过的约束图的建议。 您可以创建两个
指南
,以在滚动过程中设置CardView的开始和结束位置。让我举例说明视图开始位置的XML

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:clipChildren="false"
android:id="@+id/containerLayout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
tools:ignore="MissingPrefix">

<android.support.constraint.Guideline
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/guideline"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.1"/>

<android.support.constraint.Guideline
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/guideline2"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.9"/>

<android.support.v7.widget.CardView
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    app:cardBackgroundColor="?android:attr/windowBackground"

    app:layout_constraintTop_toTopOf="@+id/guideline">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_height="wrap_content"
        android:layout_width="match_parent" />
</android.support.v7.widget.CardView>

在这里,我假设您希望在顶部留下大约10%的屏幕空间。如果您想要更少或更多,请调整

一旦用户开始滚动,您可以将Cardview的顶部约束调整到父级的顶部,一旦用户到达列表的底部,您可以将Cardview的底部约束调整到
指南2
,这将在下面留下10%的屏幕空间

这应该在没有太多性能问题的情况下达到预期效果,因为您正在取消Scrollview


如果您需要我更详细地阐述我的答案的任何部分,请让我知道。

根据Okensif关于操纵适配器的想法,我制作了一个适配器,有三种布局(topitem、middleitem、bottomitem),topitem和bottomitem有两个XML可绘制形状。因此,我能够完全摆脱
NestedScrollView
CardView

这就是它看起来的样子:

这是代码。首先,
main活动

public class MainActivity extends AppCompatActivity {
    final static int LIST_SIZE = 100;

    final static int TOP = 0;
    final static int BOTTOM = LIST_SIZE;
    final static int MIDDLE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity);

        final ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < LIST_SIZE; i++) {
            list.add(i);
        }

        class Viewholder extends RecyclerView.ViewHolder {
            TextView textView;

            Viewholder(View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.textView);
            }
        }

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        final RecyclerView.Adapter<Viewholder> adapter = new RecyclerView.Adapter<Viewholder>() {
            LayoutInflater inflater = LayoutInflater.from(MainActivity.this);

            @Override
            public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
                switch (viewType) {
                    case TOP:
                        return new Viewholder(inflater.inflate(R.layout.topitem, parent, false));
                    case BOTTOM:
                        return new Viewholder(inflater.inflate(R.layout.bottomitem, parent, false));
                    case MIDDLE:
                    default:
                        return new Viewholder(inflater.inflate(R.layout.middleitem, parent, false));
                }
            }

            @Override
            public void onBindViewHolder(Viewholder holder, int position) {
                holder.textView.setText(String.valueOf(list.get(position)));
                if (position != 0 && position != LIST_SIZE - 1) {
                    int color = position % 2 == 0 ? android.R.color.holo_orange_dark : android.R.color.holo_orange_light;
                    holder.itemView.setBackgroundColor(getResources().getColor(color));
                }
            }

            @Override
            public int getItemCount() {
                return LIST_SIZE;
            }

            @Override
            public int getItemViewType(int position) {
                int itemViewType;
                switch (position) {
                    case 0:
                        itemViewType = TOP;
                        break;
                    case LIST_SIZE - 1:
                        itemViewType = BOTTOM;
                        break;
                    default:
                        itemViewType = MIDDLE;
                }
                return itemViewType;
            }
        };
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
    }
}
res/layout/topitem.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:paddingLeft="25dp"
        android:paddingRight="25dp" />
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/topbackground"
    android:layout_marginTop="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bottombackground"
    android:layout_marginBottom="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_dark" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_light" />
</shape>
res/layout/bottomitem.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:paddingLeft="25dp"
        android:paddingRight="25dp" />
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/topbackground"
    android:layout_marginTop="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bottombackground"
    android:layout_marginBottom="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_dark" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_light" />
</shape>
res/drawable/bottombackground.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:paddingLeft="25dp"
        android:paddingRight="25dp" />
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/topbackground"
    android:layout_marginTop="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bottombackground"
    android:layout_marginBottom="50dp"
    android:textAlignment="center"
    android:textColor="@android:color/white"
    android:textSize="24sp"
    android:textStyle="bold" />
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_dark" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp" />
    <solid android:color="@android:color/holo_orange_light" />
</shape>
并将背景更改为白色,得到以下结果:


这只是一行简单的代码

recycler.setNestedScrollingEnabled(false);

别忘了将cardview高度设为包装内容的高度

我也面临同样的问题
android:nestedScrollingEnabled=“false”
修复了fling手势,但如果您的RecyclerView足够大,界面会非常滞后。您在这方面有什么进展吗?@pdegand 59我正在考虑一个没有NestedScrollView的解决方案,但是在
RecyclerView
中有一个滚动侦听器。当您从下向上滚动时,
cardwiew
将退出屏幕;当您到达项目的末尾时,将显示底部。这可以通过使用
cardView.animate().y(newposition).setDuration(0).start()
实现。这只是一个想法,我没有在代码上测试它。请注意,在
NestedScrollView
内部使用
RecyclerView
就像在
LinearLayout
内部使用
ScrollView
。不会进行回收,
RecyclerView
的高度为itemHeight*itemCount。如果你不担心的话,将
NestedScrollView
替换为
ScrollView
,您将有一个投掷手势。另一个不太优雅的想法是重写回收器适配器,使第一个和最后一个项目都有圆角,这个额外的空间有透明的背景。您可以尝试在单元格上有仰角的白色背景上吗?我确信在每个单元的侧面间隔处会有一些阴影重叠。这就是为什么我们的目标是在整个列表中只使用一个cardview的主要原因,因为您的阴影被剪裁在侧面。将
clipToPadding=“false”
添加到RecycleServiceWyes,您是对的。当填充未剪裁且所有三种布局上都有标高时,单元格分隔处会出现“阴影”。然而,在底部布局上使用仰角只能得到我刚刚发布的结果。这是你想要的吗?