web-dev-qa-db-fra.com

RecyclerView - Comment faire défiler en douceur le haut de l'article sur une certaine position

Sur un RecyclerView, je peux soudainement faire défiler vers le haut un élément sélectionné en utilisant:

((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);

Cependant, ceci abruptly déplace l'élément en première position. Je veux passer au sommet d'un élémenten douceur.

J'ai aussi essayé:

recyclerView.smoothScrollToPosition(position);

mais cela ne fonctionne pas bien car cela ne déplace pas l'élément vers la position sélectionnée en haut. Il fait simplement défiler la liste jusqu'à ce que l'élément sur la position soit visible.

76
Tiago

RecyclerView est conçu pour être extensible, il n’est donc pas nécessaire de sous-classer LayoutManager (comme droidev le suggère ) pour effectuer le défilement.

Au lieu de cela, créez simplement une SmoothScroller avec la préférence SNAP_TO_START:

RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(context) {
  @Override protected int getVerticalSnapPreference() {
    return LinearSmoothScroller.SNAP_TO_START;
  }
};

Maintenant, vous définissez la position où vous voulez faire défiler:

smoothScroller.setTargetPosition(position);

et transmettez ce SmoothScroller au LayoutManager:

layoutManager.startSmoothScroll(smoothScroller);
131
Paul Woitaschek

pour cela, vous devez créer un LayoutManager personnalisé

public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {

    public LinearLayoutManagerWithSmoothScroller(Context context) {
        super(context, VERTICAL, false);
    }

    public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return LinearLayoutManagerWithSmoothScroller.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}

utilisez-le pour votre RecyclerView et appelez smoothScrollToPosition.

exemple :

 recyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(context));
 recyclerView.smoothScrollToPosition(position);

cela fera défiler jusqu'en haut de l'élément RecyclerView de la position spécifiée.

j'espère que cela t'aides.

98
droidev

On peut essayer comme ça

    recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(), recyclerView.getAdapter().getItemCount());
3
Supto

Le moyen le plus simple que j'ai trouvé de faire défiler une RecyclerView est le suivant:

// Define the Index we wish to scroll to.
final int lIndex = 0;
// Assign the RecyclerView's LayoutManager.
this.getRecyclerView().setLayoutManager(this.getLinearLayoutManager());
// Scroll the RecyclerView to the Index.
this.getLinearLayoutManager().smoothScrollToPosition(this.getRecyclerView(), new RecyclerView.State(), lIndex);
3
Mapsy

Ceci est une extension des fonctions que j'ai écrites dans Kotlin pour appeler directement sur RecyclerView (basé sur la réponse de @Paul Woitaschek):

fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
    val smoothScroller = object: LinearSmoothScroller(this.context) {
        override fun getVerticalSnapPreference(): Int {
            return snapMode
        }

        override fun getHorizontalSnapPreference(): Int {
            return snapMode
        }
    }
    smoothScroller.targetPosition = position
    layoutManager?.startSmoothScroll(smoothScroller)
}

Utilisez-le comme ceci:

myRecyclerView.smoothSnapToPosition(itemPosition)
2
vovahost

j'ai utilisé comme ça:

recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, new RecyclerView.State(), 5);
0
Criss

Remplacez la fonction CalculateDyToMakeVisible/CalculateDxToMakeVisible dans LinearSmoothScroller pour implémenter la position offset Y/X. 

override fun calculateDyToMakeVisible(view: View, snapPreference: Int): Int {
    return super.calculateDyToMakeVisible(view, snapPreference) - ConvertUtils.dp2px(10f)
}
0
user2526517

L’approche @droidev est probablement la bonne, mais je souhaite simplement publier quelque chose de légèrement différent, qui effectue fondamentalement le même travail et ne nécessite pas d’extension de LayoutManager.

A NOTE ici - cela fonctionnera bien si votre élément (celui que vous souhaitez faire défiler en haut de la liste) est visible à l'écran et que vous souhaitez simplement le faire défiler automatiquement vers le haut. C'est utile lorsque le dernier élément de votre liste a une action, qui ajoute de nouveaux éléments à la même liste et que vous souhaitez concentrer l'utilisateur sur les nouveaux éléments ajoutés:

int recyclerViewTop = recyclerView.getTop();
int positionTop = recyclerView.findViewHolderForAdapterPosition(positionToScroll) != null ? recyclerView.findViewHolderForAdapterPosition(positionToScroll).itemView.getTop() : 200;
final int calcOffset = positionTop - recyclerViewTop; 
//then the actual scroll is gonna happen with (x offset = 0) and (y offset = calcOffset)
recyclerView.scrollBy(0, offset);

L'idée est simple: 1. Nous devons obtenir la coordonnée supérieure de l'élément recyclerview; 2. Nous devons obtenir la coordonnée supérieure de l'élément de vue que nous voulons faire défiler vers le haut; 3. À la fin avec le décalage calculé, nous devons faire 

recyclerView.scrollBy(0, offset);

200 est juste un exemple de valeur entière codée en dur que vous pouvez utiliser si l'élément de titulaire de la vue n'existe pas, car c'est également possible.

0
Sniper