Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Horizontal and Vertical RecyclerView under the same scroll

I have to do something like Instagram does. I have a horizontal RecyclerView for stories, and, below, a vertical RecyclerView for feed. I want to accomplish the same scroll behavior(the stories should go with feed at scroll, not stay on top as fixed). The only solution I found is NestedScrollView but it makes extremely bad performance for RecyclerViews, my screen freezes almost forever. I tried a lot of tricks found here like nestedScrollEnabled, autoLayoutMeasure etc. but nothing worked. Thanks.

like image 343
Ciobanu Razvan Avatar asked Jul 25 '18 15:07

Ciobanu Razvan


1 Answers

Sorry if this explanation is too abstract. Let me know if you need me to be more explicit.

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

So, your vertical recyclerview has the Post items (or whatever your post class is) drawn vertically, that's the easy thing to achieve. Now, for the horizontal view, you should implement a recyclerview header (check my Adapter example). The header layout will have another horizontal recyclerview.

like image 121
Tiago Ornelas Avatar answered Nov 07 '22 15:11

Tiago Ornelas