web-dev-qa-db-fra.com

ListAdapter submitList () - Comment faire défiler jusqu'au début

J'ai un problème avec mon RecyclerView et ListAdapter.

Grâce à une API, je reçois des articles dans un ordre croissant de l'ancien au plus récent.

Ma liste est ensuite actualisée en appelant la méthode submitList (items).

Cependant, comme tout est asynchrone, après avoir reçu le premier élément, le RecyclerView reste sur la position du premier élément reçu et affiché. Étant donné que dans la classe ListAdapter, il n'y a pas de rappel lorsque la méthode submitList () est terminée, je ne trouve pas un moyen de faire défiler après les mises à jour de l'un des nouveaux éléments qui ont été ajoutés.

Existe-t-il un moyen d'intercepter lorsque ListAdapter a été mis à jour?

20
gbaccetta

Non spécifique à ListAdapter, mais il devrait néanmoins fonctionner:

Utilisez simplement adapter.registerAdapterDataObserver(RecyclerView.AdapterDataObserver) et remplacez la méthode onItemXXX appropriée pour indiquer à votre RecyclerView de défiler à n'importe quelle position.

Par exemple:

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

la méthode à remplacer est appelée:

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

comme le documentation lit:

Appelé lorsque le List actuel est mis à jour.


la documentation en ligne du ListAdapter se lit comme suit:

Cette classe est un wrapper de commodité autour de AsyncListDiffer qui implémente le comportement par défaut commun de l'adaptateur pour l'accès et le comptage des éléments.

et plus tard il lit:

Les utilisateurs avancés qui souhaitent plus de contrôle sur le comportement de l'adaptateur ou fournir une classe de base spécifique doivent se référer à AsyncListDiffer, qui fournit un mappage personnalisé des événements diff aux positions de l'adaptateur.

cela signifie que vous devez étendre le RecyclerView.Adapter normal, combiné avec une implémentation personnalisée de AsyncListDiffer; et non le ListAdapter (qui est juste un wrapper de commodité, avec la fonctionnalité de base indiquée).

vous pouvez utiliser la classe ListAdapter comme modèle pour cela (ne pas l'étendre, c'est l'indice), mais la classe résultante peut ensuite être étendue et réutilisée. sinon, il n'y a aucune chance de contrôler le rappel souhaité.

3
Martin Zeitler

J'ai vérifié le code source de ListAdapter et je vois qu'il existe une méthode onCurrentListChanged .

Vous pouvez simplement le remplacer dans votre adaptateur personnalisé. Vous pouvez également transmettre un écouteur à l'adaptateur pour capturer l'événement et faire défiler votre RecyclerView jusqu'au début.

Votre adaptateur:

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
}

Créez l'adaptateur dans votre activité ou fragment:

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