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

时间:2017-11-14 09:40:47

标签: android android-recyclerview

背景

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

它们都显示相同的数据并且具有相同数量的项目,但是以不同的方式,并且单元格的大小不必相等。

我希望滚动到一个将与另一个同步,以便在一个上显示的第一个项目将始终显示在另一个上(作为第一个)。

问题

即使我已成功使它们同步(我只选择哪一个是" master",以控制另一个的滚动),滚动的方向似乎影响了方式它有效。

假设片刻具有相同的高度:

如果我向上/向左滚动,它或多或少地按照我的意图工作:

enter image description here

但是,如果我向下/向右滚动,它会让其他RecyclerView显示另一个的第一项,但通常不会作为第一项:

enter image description here

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

如果像我写的那样,细胞的大小不同,情况会变得更糟:

enter image description here

我尝试了什么

我尝试使用其他方式滚动并转到其他位置,但所有尝试都失败了。

使用smoothScrollToPosition使事情变得更糟(虽然看起来确实更好),因为如果我扔掉,在某些时候,其他RecyclerView会控制我与之交互的那个。

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

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

activity_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>

horizo​​ntal_cell.xml

<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"/>

vertical_cell.xml

<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"/>

MainActivity

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 {
                return 100
            }

            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())
                // this makes the heights of the cells different from one another:
                holder.itemView.layoutParams.height = baseHeight + (if (position % 3 == 0) 0 else baseHeight / (position % 3))
            }

            override fun getItemCount(): Int {
                return 100
            }

            override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
                return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.vertical_cell, parent, false)) {}
            }
        }
        LinearSnapHelper().attachToRecyclerView(topReccyclerView)
        LinearSnapHelper().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)
            Log.d("AppLog", "onScrollStateChanged:$thisRecyclerViewId $newState")
            when (newState) {
                RecyclerView.SCROLL_STATE_DRAGGING -> if (masterView == null) {
                    Log.d("AppLog", "setting $thisRecyclerViewId to be master")
                    masterView = thisRecyclerView
                }
                RecyclerView.SCROLL_STATE_IDLE -> if (masterView == thisRecyclerView) {
                    Log.d("AppLog", "resetting $thisRecyclerViewId from being master")
                    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
            //            Log.d("AppLog", "onScrolled:$thisRecyclerView $dx-$dy")
            val currentItem = (thisRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
            if (lastItemPos == currentItem)
                return
            lastItemPos = currentItem
            otherRecyclerView.scrollToPosition(currentItem)
//            otherRecyclerView.smoothScrollToPosition(currentItem)
            Log.d("AppLog", "currentItem:" + currentItem)
        }
    }
}

问题

  1. 如何让其他RecycerView始终拥有与当前控件相同的第一项?

  2. 如何修改代码以支持平滑滚动,而不会导致突然让其他RecyclerView成为控件的问题?

  3. 编辑:在这里用不同大小的单元更新示例代码之后(因为原来我已经接近我之前描述的那个问题了),我注意到这种对齐效果并不好

    这就是我选择使用此库正确捕捉它的原因:

    https://github.com/DevExchanges/SnappingRecyclerview

    因此,我使用&#39; GravitySnapHelper&#39;而不是LinearSnapHelper。似乎工作得更好,但仍然有同步问题,并在滚动时触摸。

    编辑: 我终于修复了所有同步问题,即使单元格大小不同,它也能正常工作。

    还有一些问题:

    1. 如果您使用一个RecyclerView,然后触摸另一个,它会有非常奇怪的滚动行为。可能比它应该滚动的方式更多。

    2. 滚动不平滑(同步时和投掷时),所以看起来不太好。

    3. 可悲的是,由于捕捉(我实际上可能只需要顶级RecyclerView),它会导致另一个问题:底部的RecyclerView可能部分显示最后一项(截图有100个项目),我可以&# 39; t滚动更多以完全显示:

    4. enter image description here

      我甚至不认为底部的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)
              }
          }
      }
      

4 个答案:

答案 0 :(得分:3)

结合两个RecyclerView,有四种移动案例:

一个。将水平回收器滚动到左侧

湾将其滚动到右侧

℃。将垂直回收器滚动到顶部

d。将其滚动到底部

案件a和c不需要照顾,因为它们开箱即用。对于案例b和d,你需要做两件事:

  1. 了解您所处的回收器(垂直或水平)以及滚动的方向(向上或向下或向左或向右)和
  2. 根据otherRecyclerView中可见项目的数量计算(列表项目的)偏移量(如果屏幕越大,偏移量也需要更大)。
  3. 搞清楚这一点有点繁琐,但结果非常直接。

        @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子句组合在一起,因为这些子句是相同的。为了便于阅读,我认为将它们分开是件好事。

    第二个问题是当“第一个”回收商仍在滚动时触摸相应的“其他”回收器时同步。以下代码(包括在上面)是相关的:

    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
        if (masterView == otherRecyclerView) {
            thisRecyclerView.stopScroll();
            otherRecyclerView.stopScroll();
            syncScroll(1, 1);
        }
        masterView = thisRecyclerView;
    }
    
    当回收者被触摸并拖动一点时,

    newState等于SCROLL_STATE_DRAGGING。因此,如果在触摸相应的“其他”回收器之后触摸(并且拖动),则第二个条件(masterView == otherRecyclerview)为真。然后两个回收者都被停止,“其他”回收者与“这个”回收者同步。

答案 1 :(得分:1)

1-)布局管理器

当前smoothScrollToPosition不会将元素置于顶部。所以让我们写一个新的布局管理器。并且让我们覆盖此布局管理器的smoothScrollToPosition

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

2-)设置

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

3-)滚动监听器

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

4-)输出

enter image description here

答案 2 :(得分:0)

在Burak&#39; TopLinearLayoutManager的基础上,但纠正OnScrollListener的逻辑,我们最终得到平滑滚动和正确捕捉(水平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<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);
        }
    }
}

答案 3 :(得分:0)

另一个在我的设备中运行良好的简单解决方案

<强>可变

RecyclerView horizontalRecyclerView, verticalRecyclerView;
LinearLayoutManager horizontalLayoutManager, verticalLayoutManager;

ArrayList<String> arrayList = new ArrayList<>();
ArrayList<String> arrayList2 = new ArrayList<>();

RecyclerView代码

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);
RecyclerView.addOnScrollListener

中的

逻辑

 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>