首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RecyclerView StaggeredGridLayoutManager重排序问题

RecyclerView StaggeredGridLayoutManager重排序问题
EN

Stack Overflow用户
提问于 2015-01-06 14:17:25
回答 2查看 18.6K关注 0票数 17

我试图在带有两个列的RecyclerView中显示三个项(至少是有问题的)。第一项跨越两行。下面是它的样子:

现在,我把“第二项”移到最上面。下面是我在适配器中调用的代码(这是我编写的一个示例,演示了我在一个更复杂的项目中遇到的问题):

代码语言:javascript
复制
private int findById(int id) {
    for (int i = 0; i < items.size(); ++i) {
        if (items.get(i).title.equals("Item " + id)) {
            return i;
        }
    }

    return -1;
}

// Moving the item "Item 2" with id = 2 and position = 0
public void moveItem(int id, int position) {
    final int idx = findById(id);
    final Item item = items.get(idx);

    if (position != idx) {
        items.remove(idx);
        items.add(position, item);
        notifyItemMoved(idx, position);
        //notifyDataSetChanged();
    }
}

之后,数组很好:[Item 2, Item 1, Item 3]。然而,这一观点远非很好:

如果我触摸到RecyclerView (如果没有足够的项来滚动,就会触发超滚动效果),项目2将移到左边,在这里我希望首先看到它(有一个很好的动画):

正如您在代码中可能看到的那样,我试图通过调用notifyItemMoved(idx, position)来替换notifyDataSetChanged()。这是可行的,但变化不是动画片。

我编写了一个完整的示例来演示这一点,并将其放在GitHub上。这几乎是最小的(有一些选项可以移动项目并切换它们的范围)。

我不知道我做错了什么。这是StaggeredGridLayoutManager的一个bug吗?我想避免notifyDataSetChanged(),因为我想保持一致性的动画。

编辑:经过一些挖掘,没有必要有一个全跨度的项目来显示问题。我把整段时间都移走了。当我试图将项目2移动到0位置时,它不会移动:项目1在后面移动,项目3在右边移动,所以我有:空单元格、项目2、新行、项目1、项3。在滚动后,我仍然有正确的布局。

更有趣的是,我没有GridLayoutManager的问题。我需要一个全跨度的项目,所以它不是一个解决方案,但我想它确实是StaggeredGridLayoutManager…中的一个bug。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-11 17:13:42

我没有一个完整的答案,但我可以指出一个解决办法和错误报告(我认为这是相关的)。

要更新布局,使其看起来像第二个屏幕快照,诀窍是在调用invalidateSpanAssignments()之后调用StaggeredGridLayoutManger上的notifyItemMoved() (sglm)。“挑战”是,如果您在nIM()之后立即调用它,它将不会运行。如果你把电话延迟几毫秒,它会的。因此,在您为MainActivity引用的代码中,我将您的sglm设置为一个私有字段:

代码语言:javascript
复制
private StaggeredGridLayoutManager sglm;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    adapter = new Adapter();
    recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    sglm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    recyclerView.setLayoutManager(sglm);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setAdapter(adapter);
}

在开关块中,在处理程序中引用它:

代码语言:javascript
复制
        case R.id.move_sec_top:
            adapter.moveItem(2, 0);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    sglm.invalidateSpanAssignments();
                }
            }, 100);
            return true;

其结果是,您的动画仍然运行,布局以您想要的方式结束。这是一个真正的传说,但它确实有效。我相信这是我在以下链接中发现和报告的同一个bug:

https://code.google.com/p/android/issues/detail?id=93156

虽然我的“症状”和所需的呼叫是不同的,但根本的问题似乎是相同的。

祝好运!

编辑:不需要postDelayed,只需发布就可以了:

代码语言:javascript
复制
        case R.id.move_sec_top:
            adapter.moveItem(2, 0);
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    sglm.invalidateSpanAssignments();
                }
            });
            return true;

我最初的理论是,在布局传递结束之前,呼叫被阻塞,但我相信情况并非如此。相反,我现在认为,如果您立即调用invalidateSpanAssignments(),它实际上执行得太快(在布局更改完成之前)。因此,上面的post (毫不延迟)简单地将调用添加到呈现队列的末尾,在布局之后会发生调用。

票数 13
EN

Stack Overflow用户

发布于 2016-08-11 16:04:44

我就是这样做的。

代码语言:javascript
复制
StaggeredGridLayoutManager gaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
gaggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
recyclerView.setLayoutManager(gaggeredGridLayoutManager);

dataList = YourDataList (Your Code for Arraylist);

recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerAdapter = new DataAdapter(dataList, recyclerView);
recyclerView.setAdapter(recyclerAdapter);

// Magic line
recyclerView.addOnScrollListener(new ScrollListener());

为自定义RecyclerView滚动侦听器创建类。

代码语言:javascript
复制
private class ScrollListener extends RecyclerView.OnScrollListener {
   @Override
   public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        gaggeredGridLayoutManager.invalidateSpanAssignments();
   }
}

希望这能帮到你。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27800575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档