Android 如何同步2个RecyclerViews的第一个滚动位置? 背景

Android 如何同步2个RecyclerViews的第一个滚动位置? 背景,android,android-recyclerview,Android,Android Recyclerview,我有两个RecyclerView实例。一个是水平的,第二个是垂直的 它们都显示相同的数据,并且具有相同数量的项目,但方式不同,并且每个单元格的大小不一定相等 我希望在其中一个屏幕上滚动会与另一个屏幕同步,这样在其中一个屏幕上显示的第一个项目将始终显示在另一个屏幕上(作为第一个) 问题 即使我已经成功地使它们同步(我只是选择哪一个是“主控”,以控制另一个的滚动),滚动的方向似乎会影响它的工作方式 假设有一段时间,这些单元格具有相同的高度: 如果我向上/向左滚动,它或多或少会按照我的预期工作: 但

我有两个RecyclerView实例。一个是水平的,第二个是垂直的

它们都显示相同的数据,并且具有相同数量的项目,但方式不同,并且每个单元格的大小不一定相等

我希望在其中一个屏幕上滚动会与另一个屏幕同步,这样在其中一个屏幕上显示的第一个项目将始终显示在另一个屏幕上(作为第一个)

问题 即使我已经成功地使它们同步(我只是选择哪一个是“主控”,以控制另一个的滚动),滚动的方向似乎会影响它的工作方式

假设有一段时间,这些单元格具有相同的高度:

如果我向上/向左滚动,它或多或少会按照我的预期工作:

但是,如果我向下/向右滚动,它确实会让other RecyclerView显示other的第一项,但通常不会显示为第一项:

注意:在上面的屏幕截图中,我已经在底部的RecyclerView中滚动,但是顶部的结果类似

如我所写,如果单元格大小不同,情况会变得更糟:

我试过的 我试着使用其他的滚动方式和转到其他位置,但所有的尝试都失败了

使用smoothScrollToPosition会让事情变得更糟(尽管它看起来确实更好),因为如果我抛出,在某个点上,另一个RecyclerView会控制我与之交互的那个

我想我应该使用滚动的方向,以及其他RecyclerView上当前显示的项目

这是当前的(示例)代码。请注意,在实际代码中,单元格的大小可能不相等(一些是高的,一些是短的,等等)。代码中的一行使单元格具有不同的高度

活动\u main.xml

<android.support.constraint.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_width="match_parent"
    android:layout_height="match_parent" tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/topReccyclerView" android:layout_width="0dp" android:layout_height="100dp"
        android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp"
        android:orientation="horizontal" app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" tools:listitem="@layout/horizontal_cell"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/bottomRecyclerView" android:layout_width="0dp" android:layout_height="0dp"
        android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp"
        android:layout_marginTop="8dp" app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/topReccyclerView"
        tools:listitem="@layout/horizontal_cell"/>
</android.support.constraint.ConstraintLayout>
<TextView
    android:id="@+id/textView" xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="100dp" android:layout_height="100dp"
    android:gravity="center" tools:text="@tools:sample/lorem"/>
<TextView
    android:id="@+id/textView" xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="50dp"
    android:gravity="center" tools:text="@tools:sample/lorem"/>

因此,我使用“GravitySnapHelper”代替LinearSnapHelper。似乎工作得更好,但仍有同步问题,滚动时触摸


编辑: 我终于解决了所有同步问题,即使单元格大小不同,它也可以正常工作

仍然存在一些问题:

  • 如果你打开一个RecyclerView,然后触摸另一个,它会有非常奇怪的滚动行为。可能比它应该滚动的更多

  • 滚动不平滑(同步和投掷时),因此看起来不太好

  • 遗憾的是,由于抓拍(我实际上可能只需要顶部的RecyclerView),它会导致另一个问题:底部的RecyclerView可能会部分显示最后一个项目(包含100个项目的屏幕截图),我无法滚动更多以完全显示它:

  • 我甚至不认为底部的RecyclerView应该被打断,除非顶部的那一个被触碰了。遗憾的是,到目前为止,我只得到了这些,没有同步问题

    在我找到所有修复程序后,以下是新代码:

    class MainActivity : AppCompatActivity() {
        var masterView: View? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val inflater = LayoutInflater.from(this)
            topReccyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
                override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                    (holder.itemView as TextView).text = position.toString()
                    holder.itemView.setBackgroundColor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())
                }
    
                override fun getItemCount(): Int = 1000
    
                override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
                    return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.horizontal_cell, parent, false)) {}
                }
            }
    
            bottomRecyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
                val baseHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()
                override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                    (holder.itemView as TextView).text = position.toString()
                    holder.itemView.setBackgroundColor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())
                    holder.itemView.layoutParams.height = baseHeight + (if (position % 3 == 0) 0 else baseHeight / (position % 3))
                }
    
                override fun getItemCount(): Int = 1000
    
                override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
                    return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.vertical_cell, parent, false)) {}
                }
            }
            // GravitySnapHelper is available from : https://github.com/DevExchanges/SnappingRecyclerview
            GravitySnapHelper(Gravity.START).attachToRecyclerView(topReccyclerView)
            GravitySnapHelper(Gravity.TOP).attachToRecyclerView(bottomRecyclerView)
            topReccyclerView.addOnScrollListener(OnScrollListener(topReccyclerView, bottomRecyclerView))
            bottomRecyclerView.addOnScrollListener(OnScrollListener(bottomRecyclerView, topReccyclerView))
        }
    
        inner class OnScrollListener(private val thisRecyclerView: RecyclerView, private val otherRecyclerView: RecyclerView) : RecyclerView.OnScrollListener() {
            var lastItemPos: Int = Int.MIN_VALUE
            val thisRecyclerViewId = resources.getResourceEntryName(thisRecyclerView.id)
    
            override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                when (newState) {
                    RecyclerView.SCROLL_STATE_DRAGGING -> if (masterView == null) {
                        masterView = thisRecyclerView
                    }
                    RecyclerView.SCROLL_STATE_IDLE -> if (masterView == thisRecyclerView) {
                        masterView = null
                        lastItemPos = Int.MIN_VALUE
                    }
                }
            }
    
            override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dx == 0 && dy == 0 || masterView !== null && masterView !== thisRecyclerView) {
                    return
                }
                val otherLayoutManager = otherRecyclerView.layoutManager as LinearLayoutManager
                val thisLayoutManager = thisRecyclerView.layoutManager as LinearLayoutManager
                val currentItem = thisLayoutManager.findFirstCompletelyVisibleItemPosition()
                if (lastItemPos == currentItem) {
                    return
                }
                lastItemPos = currentItem
                otherLayoutManager.scrollToPositionWithOffset(currentItem, 0)
            }
        }
    }
    
    class MainActivity:AppCompatActivity(){
    var主视图:视图?=null
    重写创建时的乐趣(savedInstanceState:Bundle?){
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val充气机=从(此)开始的充气机
    TopRecycleView.adapter=对象:RecycleView.adapter(){
    覆盖onBindViewHolder(holder:RecyclerView.ViewHolder,位置:Int){
    (holder.itemView为TextView).text=position.toString()
    holder.itemView.setBackgroundColor(如果(位置%2==0)0xffff0000.toInt()否则0xff00ff00.toInt())
    }
    重写getItemCount():Int=1000
    重写CreateViewHolder(父级:ViewGroup?,viewType:Int):RecyclerView.ViewHolder{
    返回对象:RecyclerView.ViewHolder(充气器.充气(R.layout.horizontal_单元格,父项,false)){}
    }
    }
    bottomRecyclerView.adapter=对象:RecyclerView.adapter(){
    val baseHeight=TypedValue.applyDimension(TypedValue.COMPLEX\u UNIT\u DIP,50f,resources.displayMetrics).toInt()
    覆盖onBindViewHolder(holder:RecyclerView.ViewHolder,位置:Int){
    (holder.itemView为TextView).text=position.toString()
    holder.itemView.setBackgroundColor(如果(位置%2==0)0xffff0000.toInt()否则0xff00ff00.toInt())
    holder.itemView.layoutParams.height=baseHeight+(如果(位置%3==0)0否则baseHeight/(位置%3))
    }
    重写getItemCount():Int=1000
    重写CreateViewHolder(父级:ViewGroup?,viewType:Int):RecyclerView.ViewHolder{
    返回对象:RecyclerView.ViewHolder(充气器.充气(R.layout.vertical_单元格,父项,false)){}
    }
    }
    //GravitySnapHelper可从以下网站获得:https://github.com/DevExchanges/SnappingRecyclerview
    GravitySnapHelper(Gravity.START).attachToRecyclerView(TopRecyclerView)
    GravitySnapHelper(Gravity.TOP)。attachToRecyclerView(bottomRecyclerView)
    addOnScrollListener(OnScrollListener(TopRecyclerView,bottomRecyclerView))
    addOnScrollListener(OnScrollListener(bottomRecyclerView,TopRecyclerView))
    }
    内部类OnScrollListener(private val thisRecyclerView:RecyclerView,private val otherRecyclerView:RecyclerView):RecyclerView.OnScrollListener(){
    var lastItemPos:Int=Int.MIN\u值
    val thisRecycleServiceWid=resources.getResourceEntryName(thisRecycleServiceView.id)
    覆盖CrollStateChanged(recyclerView:recyclerView?,newState:Int){
    super.onScrollStateChanged(recyclerView、newState)
    何时(新闻状态){
    RecyclerView.SCROLL\u STATE\u drawing->if(主视图==null){
    主视图=此回收视图
    }
    RecyclerView.SCROLL\u STATE\u IDLE->if(主视图==此RecyclerView){
    
    class MainActivity : AppCompatActivity() {
        var masterView: View? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val inflater = LayoutInflater.from(this)
            topReccyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
                override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                    (holder.itemView as TextView).text = position.toString()
                    holder.itemView.setBackgroundColor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())
                }
    
                override fun getItemCount(): Int = 1000
    
                override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
                    return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.horizontal_cell, parent, false)) {}
                }
            }
    
            bottomRecyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
                val baseHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f, resources.displayMetrics).toInt()
                override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                    (holder.itemView as TextView).text = position.toString()
                    holder.itemView.setBackgroundColor(if (position % 2 == 0) 0xffff0000.toInt() else 0xff00ff00.toInt())
                    holder.itemView.layoutParams.height = baseHeight + (if (position % 3 == 0) 0 else baseHeight / (position % 3))
                }
    
                override fun getItemCount(): Int = 1000
    
                override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
                    return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.vertical_cell, parent, false)) {}
                }
            }
            // GravitySnapHelper is available from : https://github.com/DevExchanges/SnappingRecyclerview
            GravitySnapHelper(Gravity.START).attachToRecyclerView(topReccyclerView)
            GravitySnapHelper(Gravity.TOP).attachToRecyclerView(bottomRecyclerView)
            topReccyclerView.addOnScrollListener(OnScrollListener(topReccyclerView, bottomRecyclerView))
            bottomRecyclerView.addOnScrollListener(OnScrollListener(bottomRecyclerView, topReccyclerView))
        }
    
        inner class OnScrollListener(private val thisRecyclerView: RecyclerView, private val otherRecyclerView: RecyclerView) : RecyclerView.OnScrollListener() {
            var lastItemPos: Int = Int.MIN_VALUE
            val thisRecyclerViewId = resources.getResourceEntryName(thisRecyclerView.id)
    
            override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                when (newState) {
                    RecyclerView.SCROLL_STATE_DRAGGING -> if (masterView == null) {
                        masterView = thisRecyclerView
                    }
                    RecyclerView.SCROLL_STATE_IDLE -> if (masterView == thisRecyclerView) {
                        masterView = null
                        lastItemPos = Int.MIN_VALUE
                    }
                }
            }
    
            override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dx == 0 && dy == 0 || masterView !== null && masterView !== thisRecyclerView) {
                    return
                }
                val otherLayoutManager = otherRecyclerView.layoutManager as LinearLayoutManager
                val thisLayoutManager = thisRecyclerView.layoutManager as LinearLayoutManager
                val currentItem = thisLayoutManager.findFirstCompletelyVisibleItemPosition()
                if (lastItemPos == currentItem) {
                    return
                }
                lastItemPos = currentItem
                otherLayoutManager.scrollToPositionWithOffset(currentItem, 0)
            }
        }
    }
    
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                if (masterView == otherRecyclerView) {
                    thisRecyclerView.stopScroll();
                    otherRecyclerView.stopScroll();
                    syncScroll(1, 1);
                }
                masterView = thisRecyclerView;
            } else if (newState == RecyclerView.SCROLL_STATE_IDLE && masterView == thisRecyclerView) {
                masterView = null;
            }
        }
    
        @Override
        public void onScrolled(RecyclerView recyclerview, int dx, int dy) {
            super.onScrolled(recyclerview, dx, dy);
            if ((dx == 0 && dy == 0) || (masterView != null && masterView != thisRecyclerView)) {
                return;
            }
            syncScroll(dx, dy);
        }
    
        void syncScroll(int dx, int dy) {
            LinearLayoutManager otherLayoutManager = (LinearLayoutManager) otherRecyclerView.getLayoutManager();
            LinearLayoutManager thisLayoutManager = (LinearLayoutManager) thisRecyclerView.getLayoutManager();
            int offset = 0;
            if ((thisLayoutManager.getOrientation() == HORIZONTAL && dx > 0) || (thisLayoutManager.getOrientation() == VERTICAL && dy > 0)) {
                // scrolling horizontal recycler to left or vertical recycler to bottom
                offset = otherLayoutManager.findLastCompletelyVisibleItemPosition() - otherLayoutManager.findFirstCompletelyVisibleItemPosition();
            }
            int currentItem = thisLayoutManager.findFirstCompletelyVisibleItemPosition();
            otherLayoutManager.scrollToPositionWithOffset(currentItem, offset);
        }
    
    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
        if (masterView == otherRecyclerView) {
            thisRecyclerView.stopScroll();
            otherRecyclerView.stopScroll();
            syncScroll(1, 1);
        }
        masterView = thisRecyclerView;
    }
    
    public class TopLinearLayoutManager extends LinearLayoutManager
    {
        public TopLinearLayoutManager(Context context, int orientation)
        {
            //orientation : vertical or horizontal
            super(context, orientation, false);
        }
    
        @Override
        public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
        {
            RecyclerView.SmoothScroller smoothScroller = new TopSmoothScroller(recyclerView.getContext());
            smoothScroller.setTargetPosition(position);
            startSmoothScroll(smoothScroller);
        }
    
        private class TopSmoothScroller extends LinearSmoothScroller
        {
            TopSmoothScroller(Context context)
            {
                super(context);
            }
    
            @Override
            public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference)
            {
                return (boxStart - viewStart);
            }
        }
    }
    
        //horizontal one
        RecyclerView rvMario = (RecyclerView) findViewById(R.id.rvMario);
    
        //vertical one
        RecyclerView rvLuigi = (RecyclerView) findViewById(R.id.rvLuigi);
    
        final LinearLayoutManager managerMario = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.HORIZONTAL, false);
        rvMario.setLayoutManager(managerMario);
        ItemMarioAdapter adapterMario = new ItemMarioAdapter(itemList);
        rvMario.setAdapter(adapterMario);
    
         //Snap to start by using Ruben Sousa's RecyclerViewSnap
        SnapHelper snapHelper = new GravitySnapHelper(Gravity.START);
        snapHelper.attachToRecyclerView(rvMario);
    
        final TopLinearLayoutManager managerLuigi = new TopLinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL);
        rvLuigi.setLayoutManager(managerLuigi);
        ItemLuigiAdapter adapterLuigi = new ItemLuigiAdapter(itemList);
        rvLuigi.setAdapter(adapterLuigi);
    
    rvMario.addOnScrollListener(new RecyclerView.OnScrollListener()
    {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy)
        {
         super.onScrolled(recyclerView, dx, dy);
    
         //get firstCompleteleyVisibleItemPosition
         int firstCompleteleyVisibleItemPosition = managerMario.findFirstCompletelyVisibleItemPosition();
    
         if (firstCompleteleyVisibleItemPosition >= 0)
         {  
          //vertical one, smooth scroll to position
          rvLuigi.smoothScrollToPosition(firstCompleteleyVisibleItemPosition);
         }
        }
    
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState)
        {
         super.onScrollStateChanged(recyclerView, newState);
        }
    });
    
    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<RecyclerView.ViewHolder>() {
                @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);
            }
        }
    }
    
    RecyclerView horizontalRecyclerView, verticalRecyclerView;
    LinearLayoutManager horizontalLayoutManager, verticalLayoutManager;
    
    ArrayList<String> arrayList = new ArrayList<>();
    ArrayList<String> arrayList2 = new ArrayList<>();
    
    horizontalRecyclerView = findViewById(R.id.horizontalRc);
    verticalRecyclerView = findViewById(R.id.verticalRc);
    
    horizontalRecyclerView.setHasFixedSize(true);
    verticalRecyclerView.setHasFixedSize(true);
    
    horizontalLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    verticalLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    
    horizontalRecyclerView.setLayoutManager(horizontalLayoutManager);
    verticalRecyclerView.setLayoutManager(verticalLayoutManager);
    
    for (int i = 0; i < 50; i++) {
         arrayList.add("" + i);
         arrayList2.add("" + i);
     }
    
     MyDataAdapter horizontalAdapter = new MyDataAdapter(this, arrayList);
     MyDataAdapter verticalAdapter = new MyDataAdapter(this, arrayList2);
    
     horizontalRecyclerView.setAdapter(horizontalAdapter);
     verticalRecyclerView.setAdapter(verticalAdapter);
    
     horizontalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = horizontalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    verticalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
                }
    
            });
    
    
            verticalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = verticalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    horizontalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
    
                }
            });
    
    public class Main4Activity extends AppCompatActivity {
    
        RecyclerView horizontalRecyclerView, verticalRecyclerView;
        LinearLayoutManager horizontalLayoutManager, verticalLayoutManager;
    
        ArrayList<String> arrayList = new ArrayList<>();
        ArrayList<String> arrayList2 = new ArrayList<>();
    
        boolean isVertical = true, isHorizontal = true;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main4);
    
    
            horizontalRecyclerView = findViewById(R.id.horizontalRc);
            verticalRecyclerView = findViewById(R.id.verticalRc);
    
            horizontalRecyclerView.setHasFixedSize(true);
            verticalRecyclerView.setHasFixedSize(true);
    
            horizontalLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
            verticalLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    
            horizontalRecyclerView.setLayoutManager(horizontalLayoutManager);
            verticalRecyclerView.setLayoutManager(verticalLayoutManager);
    
            for (int i = 0; i < 50; i++) {
                arrayList.add("" + i);
                arrayList2.add("" + i);
            }
    
            MyDataAdapter horizontalAdapter = new MyDataAdapter(this, arrayList);
            MyDataAdapter verticalAdapter = new MyDataAdapter(this, arrayList2);
    
            horizontalRecyclerView.setAdapter(horizontalAdapter);
            verticalRecyclerView.setAdapter(verticalAdapter);
    
            horizontalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = horizontalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    verticalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
    
                }
    
            });
    
    
            verticalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = verticalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    horizontalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
    
                }
            });
    
    
    
           /* horizontalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = horizontalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    verticalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
                    *//*if (isHorizontal) {
                        int pos = horizontalLayoutManager.findFirstCompletelyVisibleItemPosition();
                        verticalLayoutManager.scrollToPositionWithOffset(pos, 20);
                        Log.e("isHorizontal", "TRUE");
                        isVertical = false;
                    } else {
                        isHorizontal = true;
                    }*//*
    
                }
    
               *//* @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    isVertical = true;
                }*//*
            });
    
    
            verticalRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
                *//* @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     super.onScrollStateChanged(recyclerView, newState);
                     isHorizontal = true;
                 }
     *//*
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                    int pos = verticalLayoutManager.findFirstCompletelyVisibleItemPosition();
                    horizontalLayoutManager.scrollToPositionWithOffset(pos, 20);
    
                   *//* if (isVertical) {
                        int pos = verticalLayoutManager.findFirstCompletelyVisibleItemPosition();
                        horizontalLayoutManager.scrollToPositionWithOffset(pos, 20);
                        Log.e("isVertical", "TRUE");
                        isHorizontal = false;
                    } else {
                        isVertical = true;
                    }*//*
    
    
                }
            });*/
    
    
        }
    }
    
    public class MyDataAdapter extends RecyclerView.Adapter<MyDataAdapter.ViewHolder> {
    
        Context context;
        ArrayList<String> arrayList;
    
    
        public MyDataAdapter(Context context, ArrayList<String> arrayList) {
            this.context = context;
            this.arrayList = arrayList;
        }
    
        @Override
        public MyDataAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(context).inflate(R.layout.temp, parent, false);
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(MyDataAdapter.ViewHolder holder, int position) {
    
            if (position % 2 == 0) {
                holder.tvNumber.setBackgroundResource(R.color.colorGreen);
            } else {
                holder.tvNumber.setBackgroundResource(R.color.colorRed);
            }
            holder.tvNumber.setText(arrayList.get(position));
        }
    
        @Override
        public int getItemCount() {
            return arrayList.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
    
            TextView tvNumber;
    
            public ViewHolder(View itemView) {
                super(itemView);
                tvNumber = itemView.findViewById(R.id.tvNumber);
            }
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/horizontalRc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone" />
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/verticalRc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="20dp"
            android:visibility="gone" />
    
    
    
    </LinearLayout>    
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="40dp">
    
        <TextView
            android:id="@+id/tvNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="50dp" />
    
    
    </LinearLayout>
    
    <color name="colorGreen">#307832</color>
    <color name="colorRed">#ff4c4c</color>