圆形(无尽的)回收者视图

时间:2017-11-06 12:27:59

标签: android android-recyclerview recycler-adapter

我试图实现无限循环RecyclerView但却无法正常工作。这就是我到目前为止所拥有的:

// ----------
// Setup
// ----------

private final IntHolder mEndlessScrollRealItemCount = new IntHolder(0);
// TODO: should be calculated instead; makes sure, that there are enough items above and below the real content to fill the screen
private final int mEndlessScrollExtraItemsTopBottom = 15; 

// ------------
// Adapter
// ------------

mAdapter = new FastItemAdapter<IItem>() {

            @Override
            public int getItemCount() {
                if (super.getItemCount() == 0) {
                    mEndlessScrollRealItemCount.set(0);
                    return 0;
                }
                mEndlessScrollRealItemCount.set(super.getItemCount());
                return super.getItemCount() + 2 * mEndlessScrollExtraItemsTopBottom;
            }

            @Override
            public int getItemViewType(int position) {
                int index = getIndex(position);
                int realCount = super.getItemCount();
                L.d("getItemViewType - Pos => Index: %d => %d (Size: %d)", position, index, realCount);
                return super.getItemViewType(getIndex(position));
            }

            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
                super.onBindViewHolder(holder, getIndex(position), payloads);
            }

            private int getIndex(int position) {
                int realCount = super.getItemCount();
                int index = position;
                if (realCount == 0) {

                } else if (position < mEndlessScrollExtraItemsTopBottom) {
                    index = realCount - (mEndlessScrollExtraItemsTopBottom - position);
                } else if (position >= realCount + mEndlessScrollExtraItemsTopBottom) {
                    index = position - mEndlessScrollExtraItemsTopBottom - realCount;
                } else {
                    index = position - mEndlessScrollExtraItemsTopBottom;
                }
                while (index < 0) {
                    index += realCount;
                }
                index %= realCount;
                L.d("Pos => Index: %d => %d (Size: %d)", position, index, realCount);
                return index;
            }
        };
        rvSidebar.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int firstItemVisible = RecyclerViewUtil.findFirstVisibleItemPosition(rvSidebar);
                int c = mEndlessScrollRealItemCount.get();
                L.d("firstItemVisible %d, (Size: %d)", firstItemVisible, c);
                if (firstItemVisible > 0 && firstItemVisible >= c + mEndlessScrollExtraItemsTopBottom) {
                    // When position reaches end of the list, it should go back to the beginning
                    int over = firstItemVisible - (c + mEndlessScrollExtraItemsTopBottom);
                    recyclerView.scrollToPosition(mEndlessScrollExtraItemsTopBottom + over);
                    L.d("firstItemVisible scroll (end reached): %d => %d", firstItemVisible, mEndlessScrollExtraItemsTopBottom);
                } else if (firstItemVisible <= mEndlessScrollExtraItemsTopBottom - 1) {
                    // When position reaches beginning of the list, it should go back to the end
                    int before = mEndlessScrollExtraItemsTopBottom - 1 - firstItemVisible;
                    recyclerView.scrollToPosition(c + mEndlessScrollExtraItemsTopBottom - 1 - before);
                    L.d("firstItemVisible scroll (start reached): %d => %d", firstItemVisible, c + mEndlessScrollExtraItemsTopBottom - 1);
                }
            }
        });

// ----------------------------------
// Helper function in RecyclerViewUtil
// ----------------------------------

public static Integer findFirstVisibleItemPosition(RecyclerView rv)
{
    if (rv.getLayoutManager() instanceof GridLayoutManager)
        return ((GridLayoutManager)rv.getLayoutManager()).findFirstVisibleItemPosition();
    else if (rv.getLayoutManager() instanceof LinearLayoutManager)
        return ((LinearLayoutManager)rv.getLayoutManager()).findFirstVisibleItemPosition();
    return null;
}

解释

我尝试做的是:

  • 在列表之前/之后添加项目,以便在向上/向下滚动时列表中有足够的项目,以便适配器不会尝试重用项目,这仍然可见
  • 初始化RecyclerView后,我滚动到位置mEndlessScrollExtraItemsTopBottom的第一个项目,以便用户也可以向上滚动
  • 我听滚动事件并尝试移动位置,如果用户在中间或之前滚动真实列表后面使滚动看起来无穷无尽

结果

  • 向下滚动并到达核心项目的末尾,滚动位置正确移动并且无限滚动有效(但在滚动侦听器中更正滚动位置并不顺畅)
  • 向上滚动并到达核心项目的第一项,滚动位置永远不会更正(虽然计算是正确的,但recyclerView.scrollToPosition没有任何效果)

问题

  • 为什么recyclerView.scrollToPosition在向上滚动期间不起作用?
  • 如果可以解决上述问题,如何在用户滚动时顺利进行滚动位置校正?

备注

  • 我看到了将适配器项目数设置为Integer.MAX =&gt;的解决方案。我不想使用这种方法,甚至那些解决方案也需要像我一样更新滚动位置......
  • 我的解决方案基于FastAdapter,从技术上讲是正常的RecyclerView.Adapter,这应该没有任何区别

0 个答案:

没有答案