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é:
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
La modification de LayoutParams
de la vue de l'élément centré dans onScrollStateChanged
pendant l'état de défilement est IDLE
ou SETTLING
.
La dernière option restante consiste à implémenter son propre LayoutManager
personnalisé qui étendrait la valeur par défaut LayoutManager
.
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.
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 verticale: