Updated 29 March 2019
If you are in a situation in which you are required to sync your ‘n’ number of Recyclerviews in a layout then we will be discussing how you can achieve this. I have searched for this issue over the internet and there are some solutions too but I found them a little complicated and most of them don’t work properly or work for 2 RecyclerView only. So with the help of those solutions and some modifications, I have developed a way to sync all the RecyclerView in the layout with an easy and clearly understandable logic.
Suppose you have three RecyclerViews in your layout (They can be dynamically or programmatically created) as shown in the example.xml file below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/your_view_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/your_rv_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" android:orientation="horizontal" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> <android.support.v7.widget.RecyclerView android:id="@+id/your_rv_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" android:orientation="horizontal" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> <android.support.v7.widget.RecyclerView android:id="@+id/your_rv_3" android:layout_width="match_parent" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" android:orientation="horizontal" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> </LinearLayout> </android.support.v4.widget.NestedScrollView> |
Now, We will be adding a scroll listener and a tag on each of them. The scroll listener will scroll all the other RecyclerView whenever a particular RecyclerView is scrolled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
your_rv_1.setTag(0); your_rv_2.setTag(1); your_rv_3.setTag(2); your_rv_1.addOnScrollListener(your_scroll_listener); your_rv_2.addOnScrollListener(your_scroll_listener); your_rv_3.addOnScrollListener(your_scroll_listener); private RecyclerView.OnScrollListener your_scroll_listener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if ((int) recyclerView.getTag() == mTouchedRvTag) { for (int noOfRecyclerView = 0; noOfRecyclerView < 3; noOfRecyclerView++) { if (noOfRecyclerView != (int) recyclerView.getTag()) { RecyclerView tempRecyclerView = (RecyclerView) your_view_container.findViewWithTag(noOfRecyclerView); tempRecyclerView.scrollBy(dx, dy); } } } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } }; |
But there is an issue with this. Whenever a RecyclerView is scrolled, it will scroll all other RecyclerView and then the scroll listener of the other RecyclerView will also do the same and it will become an infinite loop.
To avoid this problem we need to apply a touch listener on each of the RecyclerView which will provide us the information about the RecyclerView which is being scrolled. The for loop actually goes through all the RecyclerViews and scroll each of them one by one except itself. You can also notice in the above scroll listener the code inside the onScrolled functions in executed only when the tag of that RecyclerView is same as that of the RecyclerView scrolled and the instance variable mTouchedRvTag is initialized inside the touch listener of the RecyclerView.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
your_rv_1.addOnItemTouchListener(your_touch_listener); your_rv_2.addOnItemTouchListener(your_touch_listener); your_rv_3.addOnItemTouchListener(your_touch_listener); private RecyclerView.OnItemTouchListener your_touch_listener = new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { mTouchedRvTag = (int) rv.getTag(); return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }; |
In the above code segment, we have just changed the value of mTouchedRvTag on the touch event of the RecyclerView. We have returned false this means that the touch Event is not handled inside the interceptor and the onClickListener of the RecyclerView Items will be executed.
That’s all, by using these two listeners you can achieve the syncing of the RecyclerViews. I have tested this logic for 8 – 10 RecyclerViews and it worked fine. You can definitely try for more than that.
Thank you very much. This is Vedesh Kumar signing off.
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
8 comments
how do I initialize this mTouchedRvTag ??