【问题标题】:OnScrollListener for RecyclerView total scroll is inaccurate?RecyclerView 总滚动的 OnScrollListener 不准确?
【发布时间】:2015-05-12 10:46:30
【问题描述】:

我为 RecyclerView 实现了一个 OnScrollListener,如下所示:

new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        scrollY += dy;
    }
};

这应该将所有滚动更改相加,以便 scrollY 保持 RecyclerView 的总垂直滚动。

但是当我向下滚动到列表末尾并向上滚动时,滚动值不等于 0,而是正值(在我的测试示例中,它以 300 左右结束)。

我的实现的哪一部分是错误的?

【问题讨论】:

  • overScroll 模式是否开启?
  • overScroll我没改,所以是默认值(OVER_SCROLL_ALWAYS)。我怀疑它可能与 ViewPager 中的片段重新实例化有关,因为 Recycler 位于 ViewPager 中的片段内,我现在将仔细检查我的片段状态恢复。 OverScroll 和 OnScrollListener 是否存在已知问题?
  • 我排除了这个问题,因为我的片段永远不会被保存。我已经怀疑了,因为我使用的是 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter,但我只是仔细检查了 Logcat,它与片段 reinstanciation 无关。
  • 我仍然遇到您在问题中首先描述的问题。看起来依赖 onScrolled 回调并不能产生准确的总滚动...如果您在不抬起手指的情况下来回拖动列表,一切都会很好,但是一旦您一甩,该值就会与它不同步真的应该。还没解决。
  • @brAzzi64 是的,我也这么认为。但是,如果您使用的是 LinearLayoutManager,则有一种更准确的方法来进行这些计算。您可以使用它来获取当前的屏幕视图,然后在其中一个上调用 getTop(),您至少可以获得非常精确的视图位置

标签: android android-recyclerview onscrolllistener


【解决方案1】:

好的,我想通了,这实际上是一个时间问题。对于那些可能在某些时候遇到与我相同问题的人,这是发生的事情:

在我的片段中,我添加了一个 OnScrollListener 来将所有 dy 相加以获得 RecyclerView 的完整 scrollY 值:

new RecyclerView.OnScrollListener() {
@Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        mScrollY += dy;
    }
};

在我的 RecyclerView 行中,我想在 RecyclerView 滚动时使用这个 mScrollY 值来响应视差效果,所以我在 ViewHolder 中实现了一个 OnScrollListener,如下所示:

new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        applyParallax(mScrollY); //mScrollY is calculated by fragment's OnScrollListener
    }
};

我认为,由于 ViewHolders 被销毁并重用,因此仅在需要时添加子 OnScrollListener 是最节省资源的。

我不知道 RecyclerView 的事情是它的 OnScrollListeners 是按添加顺序处理的(事后有点明显)。由于 Fragment 的 OnScrollListener 先添加,row 的 OnScrollListeners 后添加,因此 Fragment OnScrollListener 被最后调用,导致 mScrollY 值在 被行的 OnScrollListener 处理后更新,因此错过了最后一次更新并停在倒数第二个 mScrollY 值,这是正值。

我通过像这样在片段的 OnScrollListener 中实现所有逻辑来修复它(注意,我只检查第一个孩子,因为我只需要第一行的视差效果!如果你在其他地方有更多的效果,你必须遍历 LayoutManager 中的所有当前视图):

new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        mScrollY += dy;
        LinearLayoutManager manager = ((LinearLayoutManager) mRecyclerView.getLayoutManager());
        View firstChild = manager.getChildAt(0);
        if(firstChild.getId() == R.id.fpd_title_super){
            final PostDataAdapter.MainTitleViewHolder holder = (PostDataAdapter.MainTitleViewHolder)mRecyclerView.getChildViewHolder(firstChild);
            holder.dispatchScrollY(mScrollY);
        }
    }
};

并在 ViewHolders 中实现一个方法:

public void dispatchScrollY(int scrollY){
    // handle parallax effect here
}

现在可以了。

【讨论】:

  • 如果您的滚动和视差效果仍然存在问题,您可以查看此实现:github.com/kanytu/android-parallax-recyclerview
  • 这是一个不错的库,我暂时不会使用它,因为我想尽可能坚持使用框架 api,但这可能对其有此问题的其他人有所帮助!
猜你喜欢
  • 1970-01-01
  • 2016-06-27
  • 2015-08-30
  • 2023-03-03
  • 2019-11-13
  • 2020-07-09
  • 2018-08-04
  • 1970-01-01
相关资源
最近更新 更多