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

Posted

技术标签:

【中文标题】同一滚动下的水平和垂直RecyclerView【英文标题】:Horizontal and Vertical RecyclerView under the same scroll 【发布时间】:2018-07-25 15:41:24 【问题描述】:

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

【问题讨论】:

为什么这能解决我的问题? 协调器布局最适合支持多个滚动事件。您可以使用它的 cutsom 滚动行为 【参考方案1】:

对不起,如果这个解释太抽象了。如果您需要我说得更明确一些,请告诉我。

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

因此,您的垂直回收视图具有垂直绘制的 Post 项目(或任何您的帖子类),这是很容易实现的。现在,对于水平视图,您应该实现一个 recyclerview 标头(查看我的适配器示例)。标题布局将有另一个水平回收器视图。

【讨论】:

好的。除了我应该在垂直适配器中为水平 recyclerview 定义适配器/布局管理器的方式之外,一切都很清楚。请给我这部分的小样本好吗? 我在我的答案中编辑了代码。请记住,您必须创建另一个适配器(在我的示例中是 AnotherAdaterYouNeedToCreateForTheHorizo​​ntalRecyclerView)。该适配器将包含您要显示的水平项目。 再次编辑代码。注意我添加的 feedItems 数组和 notifyFeedChanged 方法 对于帖子通知更新,我应该通知适配器从 1 到帖子大小的位置,对吧? 确实如此。除非你实现 DiffResult (medium.com/@iammert/…)【参考方案2】:

在您的 XML 布局中,尝试将“标题”回收器视图和“发布”回收器视图保留在嵌套滚动视图中。它对我有用。

    <?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_
    android:layout_
    android:background="#FFFFFF">

    <androidx.core.widget.NestedScrollView
        android:layout_
        android:layout_
        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_
            android:layout_
            android:orientation="vertical">

            <LinearLayout
                android:layout_
                android:layout_
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv"
                    android:layout_
                    android:layout_
                    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_
                    android:layout_
                    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_
                    android:layout_
                    android:layout_marginTop="8dp"
                    android:orientation="horizontal" />
            </LinearLayout>

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rvv"
                android:layout_
                android:layout_
                android:orientation="vertical" />

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

</androidx.constraintlayout.widget.ConstraintLayout>

【讨论】:

以上是关于同一滚动下的水平和垂直RecyclerView的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 如何使用 ListView 水平和 GridView 垂直滚动屏幕

水平和垂直collectionViews在同一个视图Controller

将事件路由到当前元素下的元素

html中表格水平和垂直滚动,表头垂直不动,可以水平滚动,大神们请问怎么实现啊?

UIScrollview在垂直和水平ios中滚动

水平和垂直两个方向滚动