1

I'm using a ViewPager in which each page is a category that contains an horizontal RecyclerView. Each RecyclerView contains a number of items related to the category of the page of the ViewPager it's in. Of course, when the user scrolls, it scrolls into the RecyclerView if it contains more item to scroll to, otherwise, it scrolls to the next/previous page (depending on the scroll direction).

I'd like these RecyclerViews to act as ViewPagers (at first, each page of the first ViewPager contained another ViewPager, but it gave me bad performances) :

In each RecyclerView, each "page" contains 9 items (laid out in 3 columns), and I'd like the user to only be able to scroll into the RecyclerView "page by page". It means that if he's in the first page and flings to the right, he'll scroll to the "second page" (which holds the items ranging from the position 9 to 17). In addition, the user should not be able to scroll more than one page at a time.

Is there a way to do that smoothly ? I think that the easier way to do it would be by using and overriding the SnapHelper, but I must admit that I'm not quite sure how to proceed to achieve the expected result.

Thanks !

IKIKN2
  • 145
  • 3
  • 12
  • Yes, usually nesting scrollable containers like ScrollView and ViewPager requires special handling, usually delegating touch events to the parent and children, depending on what you are doing. This is quite a strange implementation and I'm not sure if the usability you are thinking is efficient and/or possible, but there's a clue for you to start. – Chisko Nov 20 '16 at 21:46
  • And what is that clue ? – IKIKN2 Nov 21 '16 at 10:37
  • It's quite hard to imagine what you want to do. Is it similar to this: https://stackoverflow.com/q/47514072/878126 ? – android developer Nov 27 '17 at 15:31

1 Answers1

3

From the description, it's difficult to tell exactly which direction the scroll behaviour should occur but the following should give you an idea of what to do:

You can nest a RecyclerView as an item inside your RecyclerView.

In the onCreateViewHolder method of your Adapter, return an alternative ViewHolder depending on the provided viewType. For brevity, I've done this as a switch statement.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    switch (viewType) {
        case REGULAR_ITEM:
            return new RegularItemViewHolder(getRowView(parent, R.layout.list_item_regular);
        case NESTED_LIST_TYPE:
            return new NestedRecyclerViewHolder(getRowView(parent, R.layout.list_item_nested_recycler);
         ...
}

  protected View getRowView(ViewGroup parent, @LayoutRes final int layoutRes) {
    return layoutInflater.inflate(layoutRes, parent, false);
  }

ViewHolder

public class NestedRecyclerViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.my_nested_recyclerview)
    public RecyclerView recyclerView;

    public NestedRecyclerViewHolder(View itemView) {  
       super(itemView);
       ButterKnife.bind(this, itemView);
    }
 }

Then in onBindViewHolder you can setup this nested RecyclerView with a horizontal LinearLayoutManager (This is assuming you have a vertical parent RecyclerView within which you'd like one or more of the rows to be a horizontal RecyclerView).

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// find the item type based on the position
if(rowType == NESTED_LIST_TYPE) {
   NestedRecyclerViewHolder viewHolder = (NestedRecyclerViewHolder)holder;
   viewHolder.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
   viewHolder.recyclerView.setAdapter(new MyAdapter());
   // continue to set up the nested `RecyclerView` as you would a regular one
}
...

This will provide the horizontal scrolling behaviour in a vertical RecyclerView - of course you can flip these to work in the other way around by using different LinearLayoutManagers for each of the RecyclerViews.

To make it behave like a ViewPager, you'd need to use the SnapHelper as you alluded to in your question:

  1. Set the width of the list items in the nested RecyclerView's Adapter to match_parent (do this in the XML layout for the items).
  2. Initialise a LinearSnapHelper (Support library 24.1) like this:

    SnapHelper snapHelper = new LinearSnapHelper();
    snapHelper.attachToRecyclerView(viewHolder.recyclerView);
    

This will give you the behaviour where the user can only see one item at a time and allow the user to page through individual horizontal views.

HBG
  • 1,731
  • 2
  • 23
  • 35