RecyclerView,StaggeredGridLayoutManager刷新错误 [英] RecyclerView, StaggeredGridLayoutManager Refresh Bug

查看:163
本文介绍了RecyclerView,StaggeredGridLayoutManager刷新错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了支持库v7-21,并且 RecyclerView 不能正确显示. GridLayoutManager LinearLayoutManager 可以.仅当在 StaggeredGridLayoutManager 中加载我的 DataSet 然后刷新数据时,才会出现问题.数据刷新工作正常,但是 RecyclerView 的视图不在屏幕上.

I used support library v7-21 and the RecyclerView isn't showing correctly. GridLayoutManager and LinearLayoutManager is Ok. Problem only occurs when in StaggeredGridLayoutManager I Load my DataSet and then refresh the data. Data refresh is working fine but the RecyclerView's view exist out of the screen.

有人知道如何解决吗?

推荐答案

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

我有一个示例项目,可以在 https://github.com/dbleicher/recyclerview上进行演示-grid-quickreturn .但是这里有一些细节可能会帮助您.

I have an example project to demonstrate this at https://github.com/dbleicher/recyclerview-grid-quickreturn . But here are a few more details that may help you out.

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

When you add/remove an item to the RecyclerView, you should call notifyItemInserted/notifyItemRemoved to have the adapter tell the layout manager to re-layout just the affected views. For example, in the adapter:

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

如果调用此方法添加视图,并且该视图在屏幕上,则SGLM似乎可以按预期的方式插入和调整布局.但是,如果您正在查看列表的顶部并将项目添加到零位置,则该视图将在屏幕外创建(您将不会看到).您可以使用以下代码滚动到该视图:

If you call this method to add a view, and the view is on-screen, SGLM seems to work as expected inserting and adjusting the layout. If, however, you are viewing the top of the list and you add the item at position zero, the view is created off-screen (and you won't see it). You can scroll to this view with this following code:

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

(IMHO)StaggeredGridLayoutManager中存在一个错误,该错误通过添加屏幕外"项目而显示.根据yiğitboyar在此线程中的评论 https://plus.google.com/u/1/111532428576115387787/posts/6xxayUBz2iV

There is (IMHO) a bug in StaggeredGridLayoutManager that is revealed with adding items "off-screen". According to comments from yiğit boyar in this thread https://plus.google.com/u/1/111532428576115387787/posts/6xxayUBz2iV

"......如果超出范围,则布局管理器不在乎"

"...if an item is added out of bounds, layout manager does not care"

这是该错误出现的地方.使用SGLM,何时发生重新布局会出现计时问题.在我的示例代码中(上面的链接),我有一个ItemDecorator,它为最上面的项目添加了边距,因此不会被工具栏遮挡.使用上面的代码时,在插入新项目时,布局错误地在屏幕上向下"移动的项目上保留了此边距.闷闷不乐.

And here's where the bug appears. With SGLM, there is a timing issue with when the re-layout occurs. In my example code (link above) I have an ItemDecorator that adds margin to the top-most item(s) so they aren't obscured by the toolbar. When using the code above, the layout incorrectly retains this margin on the item that is moved "down" the screen when the new item(s) are inserted. Bummer.

这是在顶部添加之前的布局:

Here's the layout before adding at the top:

以下是在顶部添加项目后展示该错误的布局:

Here's the layout demonstrating the bug after adding an item at the top:

有一种解决方法,但在某种程度上无法实现使用RecyclerView的目的.基本上,如果仅在添加/删除之后调用notifyDataSetChanged,这将使SGLM使其整个布局无效.从效率的角度来看,这并非最佳选择,但确实会导致布局正确.使用以下代码:

There is a workaround, but it somewhat defeats the purpose of using a RecyclerView. Basically, if you just call notifyDataSetChanged after adds/removes, this will case SGLM to invalidate it's entire layout. This is not optimal from an efficiency perspective, but it does result in a proper layout. Using the following code:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyDataSetChanged();  // Should NOT do this, but it works!
    mSGLM.scrollToPosition(position);
}

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

Will result in the proper, post-addition layout:

希望这会有所帮助.

更新时间:2014年1月4日

如评论中所述,另一个解决方法是在执行插入后在recyclerview上调用invalidateItemDecorations().现在,似乎在插入后立即执行此操作将忽略此调用(可能是因为布局传递已在运行).如果一个人暂时推迟通话,它似乎确实可以正常工作:

As noted in the comments, another workaround is to call invalidateItemDecorations() on the recyclerview after performing the insert. Right now, it appears that doing so immediately after the insert will ignore this call (possibly because a layout pass is already running). If one defers the call briefly, it does seem to work:

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);
    }
}

这篇关于RecyclerView,StaggeredGridLayoutManager刷新错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆