6

我正在使用RecyclerViewwith AsyncListDiffer(计算和动画新旧项目之间的差异,全部在后台线程上)。

我有一个按钮来对列表进行排序。在我对其进行排序并将其重新设置为RecyclerView使用后,mDiffer.submitList(items);我还调用了recyclerView.scrollToPosition(0)or ( smoothScrollToPosition(0)),但它没有任何效果。

我认为这种行为是意料之中的,因为AsyncListDiffer在调用时可能仍在计算差异scrollToPosition(0),所以它没有效果。此外,默认情况下AsyncListDiffer不会滚动回顶部,而是将 RecyclerView 保持在相同的状态。

但是我如何告诉它在完成RecyclerView后滚动到顶部AsyncListDiffer并更新它?

4

4 回答 4

5

这在这里得到了回答:

https://stackoverflow.com/a/55264063/1181261

基本上,如果您以不同的顺序提交相同的列表,它将被忽略。所以首先你需要submit(null)然后提交你重新排序的列表。

于 2019-03-20T15:16:13.940 回答
5

我担心虽然.submitList(null)可能对您有用,但它只会刷新您的整个 RecyclerView 而不会呈现所需的动画列表更新。

解决方案是在 ListAdapter 中实现该.submitList( List<T> list)方法,如下所示:

public void submitList(@Nullable List<T> list) {
    mDiffer.submitList(list != null ? new ArrayList<>(list) : null);
}

这样,您允许 ListAdapter 保留其 currentList 并使其与 newList “差异”,从而进行动画更新,而不是与null.

于 2019-03-22T04:40:17.337 回答
2

如果您查看AsyncListDiffer's的 javadocs submitList,您会注意到第二个参数是Runnable在项目提交给适配器之后执行的 a:

/**
 * Pass a new List to the AdapterHelper. Adapter updates will be computed on a background
 * thread.
 * <p>
 * If a List is already present, a diff will be computed asynchronously on a background thread.
 * When the diff is computed, it will be applied (dispatched to the {@link ListUpdateCallback}),
 * and the new List will be swapped in.
 * <p>
 * The commit callback can be used to know when the List is committed, but note that it
 * may not be executed. If List B is submitted immediately after List A, and is
 * committed directly, the callback associated with List A will not be run.
 *
 * @param newList The new List.
 * @param commitCallback Optional runnable that is executed when the List is committed, if
 *                       it is committed.
 */

所以你想要的是这个(顺便说一句,这是在 Kotlin 中):

adapter.submitList(items) {
   // This will run after items have been set in the adapter
   recyclerView.scrollToPosition(0)
}

或在 Java 中

adapter.submitList(items, () -> {
    recyclerView.scrollToPosition(0);
});
于 2020-08-21T18:46:29.550 回答
0

在“mRecyclerView.setAdapter(adapter)”代码之后,在活动中的适配器上使用 registerAdapterDataObserver:

adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {

    public void onChanged() {
       mRecyclerView.scrollToPosition(0);
    }

    public void onItemRangeRemoved(int positionStart, int itemCount) {
        // same or similar scroll code
        }
    }
});

然后在活动的 onStop() 中取消注册观察者。

于 2021-11-14T04:40:23.817 回答