Android 带有自定义网格布局管理器的RecyclerView会丢失视图和滚动同步

Android 带有自定义网格布局管理器的RecyclerView会丢失视图和滚动同步,android,android-recyclerview,gridlayoutmanager,Android,Android Recyclerview,Gridlayoutmanager,我在ConstraintLayout中有一个包含3个RecyclerViews的活动。一个位于活动的左侧,使用垂直线性布局管理器。一个位于活动的顶部,并使用水平直线布局管理器。最后一个在第一个的右边,第二个的下面,使用一个自定义的LayoutManager,它实现了一个水平和垂直滚动的网格。这将创建一个电子表格效果,我需要RecyclerViews在一个方向上同时滚动。这在大多数情况下都有效,但有快速投掷动作的情况除外。当检测到投掷时,有两个问题: 使用自定义LayoutManager的Recy

我在ConstraintLayout中有一个包含3个RecyclerViews的活动。一个位于活动的左侧,使用垂直线性布局管理器。一个位于活动的顶部,并使用水平直线布局管理器。最后一个在第一个的右边,第二个的下面,使用一个自定义的LayoutManager,它实现了一个水平和垂直滚动的网格。这将创建一个电子表格效果,我需要RecyclerViews在一个方向上同时滚动。这在大多数情况下都有效,但有快速投掷动作的情况除外。当检测到投掷时,有两个问题:

  • 使用自定义LayoutManager的RecyclerView似乎滞后,并且在一段时间内,在此回收器中看不到任何视图。
    • 我怀疑这是因为视图的大小意味着每次大约有45个视图是可见的,所以在快速播放时,所有这些视图都在不断地被回收
  • RecyclerViews之间的滚动同步丢失,有时它们会关闭一点,但如果列表很大,则它们可能会关闭一点。这是一个更重要的问题,因为视图必须正确对齐才能对用户有用。导致这种情况的投掷速度远低于问题1
  • 现行代码 连接到所有3个RecyclerViews的滚动侦听器:

    private RecyclerView.OnScrollListener syncScrollListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (recyclerAssignment == recyclerView && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    draggingView = 1;
                } else if (recyclerGrades == recyclerView && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    draggingView = 2;
                } else if (recyclerStudent == recyclerView && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    draggingView = 3;
                }
            }
    
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (draggingView == 1 && recyclerView == recyclerAssignment) {
                    recyclerGrades.scrollBy(dx, dy);
                } else if (draggingView == 2 && recyclerView == recyclerGrades) {
                    recyclerAssignment.scrollBy(dx, dy);
                    recyclerStudent.scrollBy(dx, dy);
                } else if (draggingView == 3 && recyclerView == recyclerStudent) {
                    recyclerGrades.scrollBy(dx, dy);
                }
            }
        };
    
    自定义LayoutManager与此完全相同:

    我试过的 我注意到有可能添加OnFlingListener,但似乎fling调用了回收器的scrollBy函数,它们有不同的参数

    我试图在grid RecyclerView中检测滚动状态何时变为空闲,然后滚动其他视图,但这导致了无限循环

    进一步思考 我认为扩展RecyclerView以覆盖处理fling的方法可能是有意义的,但我不确定在该方法中要做什么才能使其正确工作

    我知道要解决问题#1,我可能必须存储更多的帧外视图。这很好,但我对LayoutManager中的逻辑如何工作感到非常困惑

    布局管理器在水平或垂直滚动时返回一个“delta”变量,注释中提到这是“用于处理抛投”,但没有进一步的注释,我认为这并没有达到预期效果


    非常感谢您对解决这两个问题的任何帮助。

    第一个问题:为什么?如果左侧和顶部回收器与中央回收器同步,为什么有三个而不是一个?你知道你可以在一个回收站有不同的布局,对吗?这是关于单元格高度还是宽度的问题?第二个问题:因为我觉得您的代码看起来不错,所以我觉得您要求我们调试您正在使用的布局管理器。我需要在我的机器上运行代码来完成这项工作。您能提供一个脚注吗?关于您的代码,唯一需要更改的是对
    super
    的两个调用。由于使用
    new
    运算符和花括号
    {}
    可以隐式地子类化
    RecyclerView.OnScrollListener
    ,并且由于(抽象)超类对于要重写的两个方法只有空的方法体,你不需要在那里打任何电话。回收器必须同步,因为顶部和左侧回收器都需要粘性,此外,顶部和中央回收器在水平滚动时必须实现分页。我真的不是在这里要求调试。我的理解是,回收商应该提前准备足够的视图来处理卷轴,但这显然没有发生。我的问题其实是为了深入了解我如何才能做到这一点。第一个问题:为什么?如果左侧和顶部回收器与中央回收器同步,为什么有三个而不是一个?你知道你可以在一个回收站有不同的布局,对吗?这是关于单元格高度还是宽度的问题?第二个问题:因为我觉得您的代码看起来不错,所以我觉得您要求我们调试您正在使用的布局管理器。我需要在我的机器上运行代码来完成这项工作。您能提供一个脚注吗?关于您的代码,唯一需要更改的是对
    super
    的两个调用。由于使用
    new
    运算符和花括号
    {}
    可以隐式地子类化
    RecyclerView.OnScrollListener
    ,并且由于(抽象)超类对于要重写的两个方法只有空的方法体,你不需要在那里打任何电话。回收器必须同步,因为顶部和左侧回收器都需要粘性,此外,顶部和中央回收器在水平滚动时必须实现分页。我真的不是在这里要求调试。我的理解是,回收商应该提前准备足够的视图来处理卷轴,但这显然没有发生。我的问题其实是想了解我如何才能做到这一点。