RecyclerView,StaggeredGridLayoutManager刷新Bug

16
我使用了支持库v7-21,但是RecyclerView没有正确显示。使用GridLayoutManagerLinearLayoutManager时没有问题。只有当在StaggeredGridLayoutManager中加载DataSet并刷新数据时才会出现问题。数据刷新很好,但是RecyclerView的视图超出了屏幕外。是否有人知道如何解决这个问题?

1
我也遇到了同样的问题... :( StaggeredGridLayoutManager 在今天是有缺陷的... - mato
2个回答

9

更新于2015年1月4日(底部)

我有一个示例项目,用于演示此功能https://github.com/dbleicher/recyclerview-grid-quickreturn。但以下几点细节可能会对您有所帮助。

当您向RecyclerView添加/删除项目时,应调用notifyItemInserted/notifyItemRemoved,以便适配器告诉布局管理器重新布局受影响的视图。例如,在适配器中:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);        
}

如果您调用此方法添加视图,并且该视图在屏幕上,则SGLM似乎按预期插入并调整布局。但是,如果您查看列表顶部并在位置零添加项目,则该视图将在屏幕外创建(您将无法看到它)。 您可以使用以下代码滚动到此视图:
public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);
    mSGLM.scrollToPosition(position);
}

在StaggeredGridLayoutManager中存在一个错误,当添加“屏幕外”项目时会显露出来。根据yiğit boyar在此线程https://plus.google.com/u/1/111532428576115387787/posts/6xxayUBz2iV中的评论所述:“如果超出范围添加了一个项目,布局管理器就不会关心它”。这就是错误出现的地方。使用SGLM时,重新布局发生的时间有问题。在我的示例代码(上面的链接)中,我有一个ItemDecorator,它为最上面的项目添加边距,以便它们不被工具栏遮挡。当使用上述代码时,布局在插入新项目时错误地保留了移动“向下”屏幕的项目的边距。很遗憾。这是添加到顶部之前的布局:Layout before adding at top 以下是添加顶部项目后演示错误的布局: Bad layout 有一个解决方法,但它有点违背使用RecyclerView的目的。基本上,如果您在添加/删除后只调用notifyDataSetChanged,这将导致SGLM无效化整个布局。从效率角度来看,这并不理想,但确实会得到正确的布局。使用以下代码:
public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyDataSetChanged();  // Should NOT do this, but it works!
    mSGLM.scrollToPosition(position);
}

这将产生正确的添加后布局:正确的布局结果

希望这能帮到你。

更新:2014-01-04

如评论中所述,另一个解决方法是在插入操作后调用RecyclerView的invalidateItemDecorations()。目前,立即在插入操作后调用该方法会忽略此调用(可能是因为已经正在进行布局传递)。如果稍微延迟一下再调用该方法,它似乎确实可以工作:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);
    mSGLM.scrollToPosition(position);

    // Items added to the top row? Better invalidate the decorator.
    // Delay to ensure that the previous layout pass has completed.
    if (position < columnCount) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mRecycler.invalidateItemDecorations();
            }
        }, 300);
    }
}

项目装饰也被缓存,因此除非项目无效,否则我们不会重新绑定它。您应该调用 rv.invalidateItemDecorations - yigit
当我在插入项目后调用rv.invalidateItemDecorations()时,该调用会被忽略,因为(我认为)从调用notifyItemInserted开始已经有一个布局过程正在进行中。如果将调用invalidateItemDecorations()延迟,它确实可以正常工作。因此,仍然存在“时间”上准确何时使装饰失效的问题。 - MojoTosh

7

我找到的一个简单的解决方案是,在为您的RecyclerView设置适配器时,需要重新设置布局管理器。


2023年了,我仍然面临着同样的问题,顺便登录一下来说声谢谢。 - undefined
1
@Mab 很高兴听到那对你有用 :) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接