I have 2 RecyclerView instances. One is horizontal, and the second is vertical.
They both show the same data and have the same amount of items,
Building on Burak's TopLinearLayoutManager, but correcting the logic of the OnScrollListener we finally get working smoothscrolling and correct snapping (of the horizontal RecyclerView).
public class MainActivity extends AppCompatActivity {
View masterView = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
final LayoutInflater inflater = LayoutInflater.from(this);
final RecyclerView topRecyclerView = findViewById(R.id.topReccyclerView);
RecyclerView.Adapter adapterTop = new RecyclerView.Adapter() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(inflater.inflate(R.layout.horizontal_cell, parent, false));
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((TextView) holder.itemView).setText(String.valueOf(position));
holder.itemView.setBackgroundColor(position % 2 == 0 ? Integer.valueOf(0xffff0000) : Integer.valueOf(0xff00ff00));
}
@Override
public int getItemCount() {
return 100;
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
};
topRecyclerView.setAdapter(adapterTop);
final RecyclerView bottomRecyclerView = findViewById(R.id.bottomRecyclerView);
RecyclerView.Adapter adapterBottom = new RecyclerView.Adapter() {
int baseHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, getResources().getDisplayMetrics());
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(inflater.inflate(R.layout.vertical_cell, parent, false));
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((TextView) holder.itemView).setText(String.valueOf(position));
holder.itemView.setBackgroundColor((position % 2 == 0) ? Integer.valueOf(0xffff0000) : Integer.valueOf(0xff00ff00));
holder.itemView.getLayoutParams().height = baseHeight + (position % 3 == 0 ? 0 : baseHeight / (position % 3));
}
@Override
public int getItemCount() {
return 100;
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
}
}
};
bottomRecyclerView.setAdapter(adapterBottom);
TopLinearLayoutManager topLayoutManager = new TopLinearLayoutManager(this, LinearLayoutManager.HORIZONTAL);
topRecyclerView.setLayoutManager(topLayoutManager);
TopLinearLayoutManager bottomLayoutManager = new TopLinearLayoutManager(this, LinearLayoutManager.VERTICAL);
bottomRecyclerView.setLayoutManager(bottomLayoutManager);
final OnScrollListener topOnScrollListener = new OnScrollListener(topRecyclerView, bottomRecyclerView);
final OnScrollListener bottomOnScrollListener = new OnScrollListener(bottomRecyclerView, topRecyclerView);
topRecyclerView.addOnScrollListener(topOnScrollListener);
bottomRecyclerView.addOnScrollListener(bottomOnScrollListener);
GravitySnapHelper snapHelperTop = new GravitySnapHelper(Gravity.START);
snapHelperTop.attachToRecyclerView(topRecyclerView);
}
class OnScrollListener extends RecyclerView.OnScrollListener {
private RecyclerView thisRecyclerView;
private RecyclerView otherRecyclerView;
int lastItemPos = Integer.MIN_VALUE;
OnScrollListener(RecyclerView thisRecyclerView, RecyclerView otherRecyclerView) {
this.thisRecyclerView = thisRecyclerView;
this.otherRecyclerView = otherRecyclerView;
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
masterView = thisRecyclerView;
} else if (newState == RecyclerView.SCROLL_STATE_IDLE && masterView == thisRecyclerView) {
masterView = null;
lastItemPos = Integer.MIN_VALUE;
}
}
@Override
public void onScrolled(RecyclerView recyclerview, int dx, int dy) {
super.onScrolled(recyclerview, dx, dy);
if ((dx == 0 && dy == 0) || (masterView != thisRecyclerView)) {
return;
}
int currentItem = ((TopLinearLayoutManager) thisRecyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
if (lastItemPos == currentItem) {
return;
}
lastItemPos = currentItem;
otherRecyclerView.getLayoutManager().smoothScrollToPosition(otherRecyclerView, null, currentItem);
}
}
}