【问题标题】:ListAdapter submitList() - How to scroll to beginningListAdapter submitList() - 如何滚动到开头
【发布时间】:2018-11-11 12:24:58
【问题描述】:

我的 RecyclerView 和 ListAdapter 有问题。

通过 API,我按从旧到新的升序接收项目。

然后通过调用 submitList(items) 方法刷新我的列表。

但是,由于一切都是异步的,所以在接收到第一个项目后,RecyclerView 会一直停留在接收到的第一个项目的位置并显示出来。 由于在 ListAdapter 类中,当 submitList() 方法完成时没有回调,所以我找不到在更新到已添加的新项目之一后滚动的方法。

有没有办法在 ListAdapter 更新时进行拦截?

【问题讨论】:

  • 添加代码。你应该为 RecyclerView 使用 ListAdapter 吗?不是用于 ListViews 的 ListAdapters 吗?也许使用recyclerview适配器? developer.android.com/reference/android/support/v7/widget/…这个东西肯定有 notifyDataSetChanged() ,注册一个 AdapterDataObserver 并调用函数滚动到最后。
  • 您好,我说的是新的 RecyclerView.ListAdapter,而不是旧的 ListView。无论如何,解决方案确实是使用 AdapterDataObserver!非常感谢。如果您将其发布为答案,我可以接受。
  • 嘿,我认为我的评论不够雄辩或不足以成为一个答案,如果你不介意,添加一些你的固定代码,一些解释什么有效并发布它作为答案:) @gbaccetta
  • 你解决了这个问题吗?我也有同样的问题。
  • @gbaccetta 您需要覆盖哪些回调?

标签: android android-recyclerview listadapter


【解决方案1】:

不特定于 ListAdapter,但它应该可以工作:

只需使用adapter.registerAdapterDataObserver(RecyclerView.AdapterDataObserver) 并覆盖相关的 onItemXXX 方法,告诉您的 RecyclerView 滚动到任何位置。

举个例子:

    adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            (recycler_view.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(positionStart, 0)
        }
    })

【讨论】:

  • 在我的情况下不起作用:由于某种原因,没有一个方法被调用
  • 那么您的适配器实现中有一个错误,它没有正确调用通知方法。如果您使用 ListAdapter,请确保您致电 submitList。如果您正在制作自己的适配器实现,那么您需要自己通知这些项目。
  • 问题在于本机 submitList() 的工作方式:如果您再次提交相同的列表,即使内容发生更改,它也不会更改(不会调用任何 notify() 方法)。
【解决方案2】:

Kotlin : 非常简单的方法。

listAdapter.submitList(yourNewList) { 
    yourRecyclerView.scrollToPosition(0) 
}

【讨论】:

  • 这是最好的答案。这正是这个回调的目的。
  • 谢谢弗洛里安。我是你的忠实粉丝。我从你那里学到了很多东西,所以我很乐意提供帮助。 YouTube 上见。
  • 我希望我能完整阅读文档? 这正是我想要的!
  • 列表更新动画,滚动到顶部操作过早怎么办?
  • 这个答案不被接受的原因是,虽然每次提交新列表时滚动到顶部都很好,但它提供的灵活性较低(例如,我只需要在新列表时滚动到顶部项目被插入、未删除或移动)。
【解决方案3】:

调用要覆盖的方法:

public void onCurrentListChanged(List<T> previousList, List<T> currentList)

documentation 写道:

在当前List 更新时调用。


ListAdapter 的内联文档内容如下:

这个类是一个围绕AsyncListDiffer 的便捷包装器,它实现了适配器常见的项目访问和计数默认行为。

后来是这样写的:

希望对适配器行为进行更多控制或提供特定基类的高级用户应参考AsyncListDiffer,它提供了从差异事件到适配器位置的自定义映射。

这意味着,您需要扩展常规 RecyclerView.Adapter,并结合 AsyncListDiffer 的自定义实现;而不是ListAdapter(它只是一个方便的包装器,具有规定的基本功能)。

可以使用ListAdapter 类作为模板(不扩展它是线索),但是生成的类可以被扩展和重用。否则没有机会控制所需的回调。

【讨论】:

  • 我不知道为什么,但我无法使用该方法。公共类 SearchAdapter 扩展 ListAdapter { // ... } 。这是我的导入:import androidx.recyclerview.widget.ListAdapter;
  • @toobsco42 这是一个public 方法,因此应该公开它。签名可能应该是ListAdapter&lt;Item, ItemViewHolder&gt; 而不是...ItemViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder.
  • 我需要它是 ListAdapter 因为它有多种视图类型,所以有多个 ViewHolder 类。我实际上正在查看源代码,这些方法不存在。它的recyclerview-1.0.0-sources.jar 我猜是这个依赖的一部分:实现'androidx.core:core:1.0.0'。
  • @toobsco42 传递通用 RecyclerView.ViewHolder 似乎是合法的,但只能传递一种数据模型......它继承了相同的 .getItemViewType()
  • 它需要在AsyncListDiffer.ListListener 中实现,而不是ListAdapter 本身。文档可能不准确......因为我在点击“转到源代码”时也找不到它。
【解决方案4】:

我检查了ListAdapter 源代码,发现有onCurrentListChanged 方法。

您可以简单地在自定义适配器中覆盖它。您还可以将侦听器传递给适配器以捕获事件并将 RecyclerView 滚动到开头。

您的适配器:

typealias ListChangeListener = () -> Unit

class Adapter(private val listChangeListener: ListChangeListener) : ListAdapter<Item, Adapter.ViewHolder>(Callback) {

    override fun onCurrentListChanged(previousList: List<Item>, currentList: List<Item>) {
        super.onCurrentListChanged(previousList, currentList)

        // Call your listener here
        listChangeListener()
    }

    // Other methods and ViewHolder class
}

在您的 Activity 或 Fragment 中创建适配器:

recyclerView.adapter = Adapter { recyclerView.scrollToPosition(0) }

【讨论】:

    猜你喜欢
    • 2022-01-03
    • 2021-11-28
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多