【问题标题】:scrollBy doesn't work properly in nested recyclerviewscrollBy 在嵌套的 recyclerview 中无法正常工作
【发布时间】:2017-06-29 08:09:01
【问题描述】:

我有一个垂直滚动的RecyclerView 和水平滚动的内部 RecyclerViews,就像这样。

通过这个实现,用户可以同步滚动每个水平的recyclerview。但是,当用户垂直滚动到父 recyclerView 时,刚刚附加在窗口上的新水平 recyclerview 不会显示在相同的滚动 x 位置。这个是正常的。因为它刚刚创建。

所以,我试图在它显示之前滚动到滚动位置。就像这样:

注意:这是在垂直方向的父recyclerview的适配器中。

 @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        CellColumnViewHolder viewHolder = (CellColumnViewHolder) holder;
        if (m_nXPosition != 0) {
             // this doesn't work properly 
             viewHolder.m_jRecyclerView.scrollBy(m_nXPosition, 0);
        }
    }

如您所见,scrollByrow 10row 11row 12row 无效13 之后,我调试了代码以找出发生了什么。当我使用 scrollBy 设置滚动位置时,childCount() 为 row 10row 11row 12row 13 所以他们不会滚动。但为什么 ?为什么别人工作?

  • 我该如何解决这个问题?
  • onViewAttachedToWindow 是滚动新附加 recyclervViews 的正确位置吗?

注意:我也测试过scrollToPosition(),没有出现这样的问题。但我不能在我的情况下使用它。因为用户可以滚动到可能不是确切位置的任何 x 位置。所以我需要使用 x 值而不是位置来设置滚动位置。

编辑:可以查看The source code

【问题讨论】:

  • 能把这段代码分享到github或者其他地方方便调试
  • 我已经编辑了我的问题。你可以检查整个代码。
  • 为什么不滚动onBind?
  • @natario ScrollBy 在 onBind() 上不起作用。因为在那个时候,布局管理器还没有测量/替换等到视图。但是,昨天我找到了解决方案。如果你想知道,我会写下我的答案。
  • 我已经在运行 API 21、22、23 和 24 的模拟器上尝试了您的源代码,但我无法重现该问题。你在哪里运行你看到这个问题的代码?设备、模拟器、API 级别?

标签: android scroll android-recyclerview


【解决方案1】:

我找到了一个使用scrollToPositionWithOffset 方法而不是使用scrollBy 的解决方案。即使两者都滚动另一个位置,它们在背面的工作过程也确实不同。

例如:如果您尝试使用 scrollBy 滚动任何像素位置并且您的 recyclerView 尚未设置任何适配器,这意味着没有任何数据要显示,因此它还没有任何项目,那么 scrollBy不起作用。 RecyclerView 使用它的 layoutManager 的scrollBy 方法。所以在我的情况下,我将LinearLayoutManager 用于水平recyclerViews。

让我们看看它在做什么:

int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getChildCount() == 0 || dy == 0) {
            return 0;
        }
        mLayoutState.mRecycle = true;
        ensureLayoutState();
        final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
        final int absDy = Math.abs(dy);
        updateLayoutState(layoutDirection, absDy, true, state);
        final int consumed = mLayoutState.mScrollingOffset
                + fill(recycler, mLayoutState, state, false);
        if (consumed < 0) {
            if (DEBUG) {
                Log.d(TAG, "Don't have any more elements to scroll");
            }
            return 0;
        }
        final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
        mOrientationHelper.offsetChildren(-scrolled);
        if (DEBUG) {
            Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
        }
        mLayoutState.mLastScrollDelta = scrolled;
        return scrolled;
    }

如您所见,scrollBy 如果当时没有任何孩子,则忽略滚动意图。

  if (getChildCount() == 0 || dy == 0) {
     return 0;
  }

另一方面,scrollToPosition 可以完美地工作,即使还没有任何设置数据。

根据Pro RecyclerView slide,以下示例完美运行。但是,您不能使用 scrollBy 来做到这一点。

void onCreate(SavedInstanceState state) {
    ....
    mRecyclerView.scrollToPosition(selectedPosition);
    mRecyclerView.setAdapter(myAdapter);
}

结果,我改了小东西用scrollToPositionWithOffset()

在此实现之前,我将精确的滚动 x 位置计算为像素。

之后,当滚动进入空闲状态时,计算第一个完整可见位置到scrollToPositionWithOffset()的第一个参数。

对于作为偏移量的第二个参数,我使用view.getLeft() 函数获取值,该函数有助于获取此视图相对于其父视图的左侧位置。

而且效果很好!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    相关资源
    最近更新 更多