同一滚动下的水平和垂直 RecyclerView

Horizontal and Vertical RecyclerView under the same scroll

我必须做一些像 Instagram 那样的事情。我有一个用于故事的水平 RecyclerView,下面是一个用于提要的垂直 RecyclerView。我想完成相同的滚动行为(故事应该在滚动时与 feed 一起,而不是固定在顶部)。我找到的唯一解决方案是 NestedScrollView 但它对 RecyclerViews 的性能非常糟糕,我的屏幕几乎永远冻结。我尝试了很多在这里找到的技巧,如 nestedScrollEnabled、autoLayoutMeasure 等,但没有任何效果。谢谢。

抱歉,如果这个解释太抽象了。如果您需要我说得更清楚一点,请告诉我。

public class VerticalAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

private static final int TYPE_HEADER = 0;
private static final int TYPE_POST = 1;

List<Post> posts;
List<FeedItems> feedItems; //this array is going to populate the horizontal recycler view. Notice that is passed it on the adapter constructor

public VerticalAdapter(List<Post> posts,List<FeedItems> feedItems) {
    this.posts = posts;
    this.feedItems = feedItems;
}

public void notifyFeedChanged(List<FeedItems> newFeedItems){
    this.feedItems.clear();
    this.feedItems = newFeedItems; //set the new feed items in the array
    notifyItemChanged(0); //tell the main recycler view "Hey, update your first position". This will cause the onBindViewHolder to be called again an thus, the new items will be set into the horizontal recycler view
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    if (viewType == TYPE_HEADER)
        return new HeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.your_header_layout, false));
    else if (viewType == TYPE_POST)
        return new PostViewHolder (LayoutInflater.from(parent.getContext()).inflate(R.layout.your_post_layout, false));

    throw new RuntimeException("Don't know this type");
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {


    if (holder instanceof HeaderViewHolder){
        //set adapter for the horizontal recycler view
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(((HeaderViewHolder) holder).recyclerView.getContext(),LinearLayoutManager.HORIZONTAL, false)
        ((HeaderViewHolder) holder).recyclerView.setLayoutManager(linearLayoutManager);

        if (((HeaderViewHolder) holder).recyclerView.getAdapter() == null){ //only create the adapter the first time. the following times update the values
            AnotherAdaterYouNeedToCreateForTheHorizontalRecyclerView adapter = new AnotherAdaterYouNeedToCreateForTheHorizontalRecyclerView(feedItems);
            ((HeaderViewHolder) holder).recyclerView.setAdapter(adapter);
        }else {
            ((HeaderViewHolder) holder).recyclerView.getAdapter().notifyDataSetChanged();
        }

    }else if (holder instanceof PostViewHolder){
        //just do the normal post binding
    }
}

@Override
public int getItemCount() {
    return posts.size() + 1; // +1 because of the header
}

@Override
public int getItemViewType(int position) {
    return position == 0 ? TYPE_HEADER : TYPE_POST;
}

private class HeaderViewHolder extends RecyclerView.ViewHolder{

    RecyclerView recyclerView;

    public HeaderViewHolder(View itemView) {
        super(itemView);
        recyclerView = itemView.findViewById(R.id.the_recycler_view_id_on_the_heaedr_layout_file);
    }
}

private class PostViewHolder extends RecyclerView.ViewHolder{

    ImageView imageView;

    public PostViewHolder(View itemView) {
        super(itemView);
        imageView = itemView.findViewById(R.id.post_image_view_or_whatever);
    }
}}

因此,您的垂直 Recyclerview 具有垂直绘制的 Post 项(或您的 post class 中的任何项),这很容易实现。现在,对于水平视图,您应该实现一个 recyclerview header(查看我的 Adapter 示例)。 header 布局将有另一个水平回收视图。

在您的 XML 布局中,尝试将 "header" 回收站视图和 "Post" 回收站视图保持在嵌套滚动视图中。对我有用。

    <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingStart="16dp"
                    android:paddingTop="8dp"
                    android:text="Welcome"
                    android:textAppearance="@style/TextAppearance.AppCompat.Large"
                    android:textColor="#000000"
                    android:textSize="24sp"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/date"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingStart="16dp"
                    android:paddingTop="8dp"
                    android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                    android:textColor="@color/black_80" />

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:orientation="horizontal" />
            </LinearLayout>

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rvv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical" />

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

</androidx.constraintlayout.widget.ConstraintLayout>