[JAVA] Corriger la position d'arrêt de smoothScrollToPosition de RecyclerView

introduction

Lorsque j'ai utilisé smoothScrollToPosition avec RecyclerView, il ne s'est arrêté qu'à mi-chemin, c'est donc un mémo lorsque je l'ai vérifié.

supposition

Utiliser LinearLayoutManager La direction du défilement est verticale

Ce que je voulais faire

Je veux m'assurer que la position d'arrêt du défilement est en haut

Comportement par défaut

Selon le sens du défilement, il peut monter ou descendre ...

Enquête de mise en œuvre interne

smoothScrollToPosition L'implémentation dans le LinearLayoutManager couramment utilisé ressemble à ceci.

LinearLayoutManager.java


@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
   LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext());
   //Définir la cible de défilement Position dans le défilement
   linearSmoothScroller.setTargetPosition(position);
   //Faire défiler à l'aide de la molette
   startSmoothScroll(linearSmoothScroller);
}

LinearSmoothScroller hérite de SmoothScroller.

SmoothScroller

SmoothScroller est une classe abstraite, et il y a une méthode appelée ʻonTargetFound` dedans.

SmoothScroller.java


public abstract static class SmoothScroller {
   ...(Abréviation)
   /**
    * Called when the target position is laid out. This is the last callback SmoothScroller
    * will receive and it should update the provided {@link Action} to define the scroll
    * details towards the target view.
    * @param targetView    The view element which render the target position.
    * @param state         Transient state of RecyclerView
    * @param action        Action instance that you should update to define final scroll action
    *                      towards the targetView
    */
   protected abstract void onTargetFound(View targetView, State state, Action action);
   ...(Abréviation)
}

SmoothScroller a plusieurs rappels, mais ce rappel est le dernier à être notifié et sera appelé lorsque la vue cible entrera dans la mise en page. Quant à ce qu'il faut faire ici, il y a un commentaire à l'effet qui met à jour l'ʻactionpassée comme argument et affine la position. Maintenant, vérifions quel type d'implémentation est spécifiquement dansLinearSmoothScroller`.

LinearSmoothScroller

LinearSmoothScroller.java


@Override
protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
    final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference());
    final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference());
    final int distance = (int) Math.sqrt(dx * dx + dy * dy);
    final int time = calculateTimeForDeceleration(distance);
    if (time > 0) {
        action.update(-dx, -dy, time, mDecelerateInterpolator);
    }
}

Il calcule la quantité requise de défilement dans les directions x et y et exécute ʻaction.update. Le contenu de l'implémentation de CalculateDx / DyToMakeVisible` à calculer est trouble, donc si vous ne regardez que les commentaires, cela ressemble à ceci.

LinearSmoothScroller.java


/**
 * Calculates the vertical scroll amount necessary to make the given view fully visible
 * inside the RecyclerView.
 *
 * @param view           The view which we want to make fully visible
 * @param snapPreference The edge which the view should snap to when entering the visible
 *                       area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
 *                       {@link #SNAP_TO_ANY}.
 * @return The vertical scroll amount necessary to make the view visible with the given
 * snap preference.
 */
public int calculateDyToMakeVisible(View view, int snapPreference) {

Il dit qu'il calculera la quantité de défilement requise avant que la vue entière du premier argument puisse être vue. Le deuxième argument indique la position où vous voulez que la vue soit finalement affichée, et choisissez parmi les trois suivants.

En regardant le getVerticalSnapPreference qui détermine le deuxième argument, cela ressemble à ceci.

LinearSmoothScroller.java


protected int getVerticalSnapPreference() {
    return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
            mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
}

Il bascule entre SNAP_TO_START et SNAP_TO_END selon le sens du défilement. En d'autres termes, à cette fin, cela peut être réalisé en modifiant (écrasant) cette snapPreference.

Conclusion

La description est devenue longue, mais j'ai trouvé que le code qui devrait réellement être implémenté est suffisant pour étendre un peu le LinearSmoothScroller par défaut.

CustomLayoutManager.kt


class CustomLayoutManager(context: Context) : LinearLayoutManager(context) {
    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State?, position: Int) {
        val linearSmoothScroller = object : LinearSmoothScroller(recyclerView.context) {
            override fun getVerticalSnapPreference(): Int = if (reverseLayout) SNAP_TO_END else SNAP_TO_START
        }
        linearSmoothScroller.targetPosition = position
        startSmoothScroll(linearSmoothScroller)
    }
}

À propos, dans cet exemple, seul reverseLayout est pris en compte, mais je pense qu'il est général de l'implémenter en tenant également compte du sens de défilement (vertical / horizontal).

Recommended Posts

Corriger la position d'arrêt de smoothScrollToPosition de RecyclerView
Maintenant, j'ai résumé les bases de RecyclerView
Pliage et dépliage du contenu de la vue Recycleur
Personnalisez la répartition du contenu de Recyclerview
Comment la valeur suivante de l'objet Time est-elle correcte?
Je veux retourner la position de défilement de UITableView!
Le monde de Clara-Rules (2)
Jugement du calendrier
Le monde de Clara-Rules (4)
Le monde de Clara-Rules (1)
Le monde de Clara-Rules (3)
Le monde de Clara-Rules (5)
L'idée du tri rapide
L'idée de jQuery
La bonne réponse pour l'argent! La bonne réponse pour l'argent! [Édition japonaise de plusieurs lignes]