Comment puis-je animer les éléments RecyclerView quand ils apparaissent?
L'animateur d'élément par défaut s'anime uniquement lorsqu'une donnée est ajoutée ou supprimée une fois les données du recycleur définies. Je suis en train de développer de nouvelles applications et je ne sais pas par où commencer.
Des idées comment y parvenir?
MODIFIER :
Selon la documentation ItemAnimator :
Cette classe définit les animations qui ont lieu sur les éléments lorsque des modifications sont apportées à l'adaptateur.
Donc, à moins que vous ajoutiez vos éléments un par un à votre RecyclerView
et que vous actualisiez la vue à chaque itération, je ne pense pas que ItemAnimator
soit la solution à votre besoin.
Voici comment animer les éléments RecyclerView
lorsqu'ils apparaissent à l'aide d'un CustomAdapter:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
private Context context;
// The items to display in your RecyclerView
private ArrayList<String> items;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public static class ViewHolder extends RecyclerView.ViewHolder
{
TextView text;
// You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
// It's the view that will be animated
FrameLayout container;
public ViewHolder(View itemView)
{
super(itemView);
container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
text = (TextView) itemView.findViewById(R.id.item_layout_text);
}
}
public CustomAdapter(ArrayList<String> items, Context context)
{
this.items = items;
this.context = context;
}
@Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.text.setText(items.get(position));
// Here you apply the animation when the view is bound
setAnimation(holder.itemView, position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(context, Android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
Et votre custom_item_layout ressemblerait à ceci:
<FrameLayout
Android:id="@+id/item_layout_container"
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<TextView
Android:id="@+id/item_layout_text"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:textAppearance="?android:attr/textAppearanceListItemSmall"
Android:gravity="center_vertical"
Android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
</FrameLayout>
Pour plus d'informations sur CustomAdapters et RecyclerView
, reportez-vous à la section training de la documentation officielle .
Problèmes de défilement rapide
L'utilisation de cette méthode peut entraîner des problèmes de défilement rapide. La vue peut être réutilisée pendant le déroulement de l'animation. Afin d'éviter cela, il est recommandé d'effacer l'animation lorsque celle-ci est détachée.
@Override
public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
{
((CustomViewHolder)holder).clearAnimation();
}
Sur CustomViewHolder:
public void clearAnimation()
{
mRootLayout.clearAnimation();
}
Ancienne réponse:
Jetez un coup d'œil à Le dépôt de Gabriele Mariotti , je suis sûr que vous trouverez ce qu'il vous faut. Il fournit des éléments ItemAnimators simples pour RecyclerView, tels que SlideInItemAnimator ou SlideScaleItemAnimator.
J'ai animé la fusion des éléments Recyclerview
lorsqu'ils apparaissent pour la première fois, comme indiqué dans le code ci-dessous. Cela sera peut-être utile à quelqu'un.
private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// Set the view to fade in
setFadeAnimation(holder.itemView);
}
private void setFadeAnimation(View view) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
Vous pouvez également remplacer setFadeAnimation()
par la setScaleAnimation()
suivante pour animer l'apparence des éléments en les redimensionnant à partir d'un point:
private void setScaleAnimation(View view) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
Le code ci-dessus présente des défauts dans la mesure où, lorsque vous faites défiler les éléments RecyclerView
, les fondus ou les échelles disparaissent toujours. Si vous le souhaitez, vous pouvez ajouter du code pour autoriser l'animation uniquement lors de la création du fragment ou de l'activité contenant la variable RecyclerView
(par exemple, obtenir l'heure système lors de la création et autoriser uniquement l'animation pour les premières millisecondes FADE_DURATION).
J'ai créé une animation à partir de pbm's answer with little modification
pour que l'animation ne soit exécutée qu'une seule fois
dans l'autre mot le Animation appear with you scroll down only
private int lastPosition = -1;
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
et dans onBindViewHolder
appeler la fonction
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// call Animation function
setAnimation(holder.itemView, position);
}
Vous pouvez ajouter un attribut Android: layoutAnimation = "@ anim/rv_item_animation" à RecyclerView comme suit:
<Android.support.v7.widget.RecyclerView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layoutAnimation="@anim/layout_animation_fall_down"
/>
merci pour l'excellent article ici: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213
Voici un bon point de départ: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/Java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.Animation
Vous n'avez même pas besoin de la bibliothèque complète, cette classe suffit . Ensuite, si vous implémentez simplement votre classe Adapter, donnez un animateur comme celui-ci:
@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}
@Override
public long getItemId(final int position) {
return getWrappedAdapter().getItemId(position);
}
vous verrez les éléments apparaître par le bas à mesure qu'ils défilent, ce qui évite également le problème du défilement rapide.
L'animation d'éléments dans la vue recyclée lorsqu'ils sont liés dans l'adaptateur peut ne pas être la meilleure idée, car cela peut entraîner une animation des éléments de la vue recyclée à des vitesses différentes. Dans mon cas, l'élément situé à la fin de la liste de recyclage se positionne plus rapidement que celui situé en haut de la liste, car ceux-ci doivent encore être déplacés, de sorte que leur apparence est désordonnée.
Le code original que j'ai utilisé pour animer chaque élément dans la vue de recyclage peut être trouvé ici:
http://frogermcs.github.io/Instagram-with-Material-Design-conign-is-getting-real/
Mais je vais copier et coller le code au cas où le lien se briserait.
STEP 1: Définissez ceci dans votre méthode onCreate afin de vous assurer que l'animation ne s'exécute qu'une fois:
if (savedInstanceState == null) {
pendingIntroAnimation = true;
}
STEP 2: Vous aurez besoin de mettre ce code dans la méthode par laquelle vous voulez démarrer l'animation:
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
Dans le lien, l'auteur est en train d'animer les icônes de la barre d'outils. Il l'a donc inséré dans cette méthode:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
inboxMenuItem = menu.findItem(R.id.action_inbox);
inboxMenuItem.setActionView(R.layout.menu_item_view);
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
return true;
}
STEP 3: Maintenant écrivez la logique pour startIntroAnimation ():
private static final int ANIM_DURATION_TOOLBAR = 300;
private void startIntroAnimation() {
btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));
int actionbarSize = Utils.dpToPx(56);
toolbar.setTranslationY(-actionbarSize);
ivLogo.setTranslationY(-actionbarSize);
inboxMenuItem.getActionView().setTranslationY(-actionbarSize);
toolbar.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(300);
ivLogo.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(400);
inboxMenuItem.getActionView().animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
startContentAnimation();
}
})
.start();
}
Mon alternative préférée:
Je préférerais animer l'ensemble de la vue de recyclage plutôt que les éléments à l'intérieur de la vue de recyclage.
Les étapes 1 et 2 restent les mêmes.
Dans STEP 3, dès que votre appel API reviendra avec vos données, je commencerai l'animation.
private void startIntroAnimation() {
recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
recyclerview.setAlpha(0f);
recyclerview.animate()
.translationY(0)
.setDuration(400)
.alpha(1f)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}
Cela animerait toute votre vue de recyclage afin qu'elle vienne du bas de l'écran.
Ajouter cette ligne à RecyclerView.xml
Android:animateLayoutChanges="true"
Étend juste votre adaptateur comme ci-dessous
public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder>
Et ajouter une super méthode à onBindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
C'est un moyen automatisé de créer un adaptateur animé comme "Basheer AL-MOMANI"
import Android.support.v7.widget.RecyclerView;
import Android.view.View;
import Android.view.ViewGroup;
import Android.view.animation.Animation;
import Android.view.animation.ScaleAnimation;
import Java.util.Random;
/**
* Created by eliaszkubala on 24.02.2017.
*/
public class AnimatedRecyclerView<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {
@Override
public T onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(T holder, int position) {
setAnimation(holder.itemView, position);
}
@Override
public int getItemCount() {
return 0;
}
protected int mLastPosition = -1;
protected void setAnimation(View viewToAnimate, int position) {
if (position > mLastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
mLastPosition = position;
}
}
}
Sans avoir de codage.
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:animation="@anim/item_animation_fall_down"
Android:animationOrder="normal"
Android:delay="15%" />
<translate
Android:fromYDelta="-20%"
Android:toYDelta="0"
Android:interpolator="@Android:anim/decelerate_interpolator"
/>
<alpha
Android:fromAlpha="0"
Android:toAlpha="1"
Android:interpolator="@Android:anim/decelerate_interpolator"
/>
<scale
Android:fromXScale="105%"
Android:fromYScale="105%"
Android:toXScale="100%"
Android:toYScale="100%"
Android:pivotX="50%"
Android:pivotY="50%"
Android:interpolator="@Android:anim/decelerate_interpolator"
/>
Utilisez dans les mises en page et recylcerview comme:
<Android.support.v7.widget.RecyclerView
Android:id="@+id/recycler_view"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layoutAnimation="@anim/layout_animation"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />