web-dev-qa-db-fra.com

Vue Recycleur - redimensionnement de la vue de l'élément pendant le défilement (pour un effet de type carrousel)

Je dois créer une vue de recyclage verticale dans laquelle la vue de l'élément au centre de l'écran doit être redimensionnée pour avoir un effet de zoom lors du défilement.

Choses que j'ai essayées mais qui n'ont pas fonctionné:

  1. Ajouter un écouteur de défilement et parcourir les vues d'élément par position, mesurer la position centrée puis mettre à jour LayoutParams de centré view.

    • RecyclerView ne permet pas de calculer la position des éléments ou de mettre à jour la vue pendant le défilement. Il lance IllegalStateException si de telles opérations sont effectuées dans onScrolled
  2. La modification de LayoutParams de la vue de l'élément centré dans onScrollStateChanged pendant l'état de défilement est IDLE ou SETTLING.

    • Cela ne met à jour la vue qu'après que le défilement a été/sera terminé, pas pendant le défilement des éléments.
  3. La dernière option restante consiste à implémenter son propre LayoutManager personnalisé qui étendrait la valeur par défaut LayoutManager.

    • Pour autant que je sache, l'implémentation de Layoutmanager personnalisé implique de traiter des calculs beaucoup plus complexes qui doivent être traités.

Toutes autres solutions ou idées seront appréciées.

20
Krupal Shah

J'ai trouvé cette réponse sur SO , ce qui a fait exactement la même chose horizontalement. Answer fournit une solution de travail qui étend LinearLayoutManager. Je l'ai un peu modifié pour adapter également les listes verticales et ça marche. S'il y a une erreur de mise en œuvre, faites-le moi savoir dans les commentaires. À votre santé!

Gestionnaire de mise en page personnalisée:

public class CenterZoomLayoutManager extends LinearLayoutManager {

    private final float mShrinkAmount = 0.15f;
    private final float mShrinkDistance = 0.9f;

    public CenterZoomLayoutManager(Context context) {
        super(context);
    }

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


    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == VERTICAL) {
            int scrolled = super.scrollVerticallyBy(dy, recycler, state);
            float midpoint = getHeight() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == HORIZONTAL) {
            int scrolled = super.scrollHorizontallyBy(dx, recycler, state);

            float midpoint = getWidth() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }

    }
}

Avec orientation horizontale: enter image description here

avec orientation verticale:

enter image description here

58
Krupal Shah