web-dev-qa-db-fra.com

Animation RecyclerView sur un clic d'article

J'essaie de mettre en œuvre ma propre animation de recyclage - j'aimerais y parvenir sans utiliser de bibliothèques externes. Voici à quoi devrait ressembler l'animation théorique .

enter image description here

L'utilisateur clique sur un élément de la liste et une animation se produit qui ouvre une autre vue.

À un niveau élevé avec un code minimal, peut-être juste un pseudo-code quel serait le processus afin de créer une animation comme ça?

Je voudrais également noter que l'animation devrait également pouvoir être inversée si l'utilisateur clique sur le même élément ou sur un autre élément

Je ne connais pas très bien la classe RecyclerView et j'aimerais en savoir plus sur elle et sur les animations qui lui sont associées.

23
AndyRoid

Solution:

La façon dont j'ai résolu ce problème était d'implémenter un écouteur View.OnClickListener à la classe ViewHolder qui extends RecyclerView.ViewHolder. Nous obtenons donc le code suivant:

public static class ExampleViewHolder extends RecyclerView.ViewHolder 
    implements View.OnClickListener {

    private int originalHeight = 0;
    private boolean isViewExpanded = false;
    private YourCustomView yourCustomView

    // ..... CODE ..... //

}

Les variables originalHeight et isViewExpanded sont utilisées dans le processus d'animation. Dans le constructeur, j'initialise la vue en View.OnClickListener ainsi:

public ExampleViewHolder(View v) {
     super(v);
     v.setOnClickListener(this);

     // Initialize other views, like TextView, ImageView, etc. here

     // If isViewExpanded == false then set the visibility 
     // of whatever will be in the expanded to GONE

     if (isViewExpanded == false) {
         // Set Views to View.GONE and .setEnabled(false)
         yourCustomView.setVisibility(View.GONE);
         yourCustomView.setEnabled(false);
     }

 }

Maintenant que le constructeur a été pris en charge, nous voulons configurer ce qui se passe lorsque l'utilisateur clique sur un élément RecyclerView individuel. Les classes qui seront utiles ici seraient les objets ValueAnimator et Animation. Nous remplaçons la méthode onClick comme ceci pour accomplir ceci:

@Override
public void onClick(final View view) {
    // If the originalHeight is 0 then find the height of the View being used 
    // This would be the height of the cardview
    if (originalHeight == 0) {
            originalHeight = view.getHeight();
        }

    // Declare a ValueAnimator object
    ValueAnimator valueAnimator;
        if (!mIsViewExpanded) {
            yourCustomView.setVisibility(View.VISIBLE);
            yourCustomView.setEnabled(true);
            mIsViewExpanded = true;
            valueAnimator = ValueAnimator.ofInt(originalHeight, originalHeight + (int) (originalHeight * 2.0)); // These values in this method can be changed to expand however much you like
        } else {
            mIsViewExpanded = false;
            valueAnimator = ValueAnimator.ofInt(originalHeight + (int) (originalHeight * 2.0), originalHeight);

            Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out

            a.setDuration(200);
            // Set a listener to the animation and configure onAnimationEnd
            a.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    yourCustomView.setVisibility(View.INVISIBLE);
                    yourCustomView.setEnabled(false);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

            // Set the animation on the custom view
            yourCustomView.startAnimation(a);
        }
        valueAnimator.setDuration(200);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                view.getLayoutParams().height = value.intValue();
                view.requestLayout();
            }
        });


        valueAnimator.start();

    }

Maintenant, lorsque vous touchez une vue de carte individuelle sur le RecyclerView (en supposant que vous avez une configuration CardView, elle devrait s'étendre. Assurez-vous de déclarer correctement votre customView dans votre fichier xml (exemple si vous voulez que le CardView pour développer vers le bas lorsque vous le touchez, puis affectez correctement la vue personnalisée sous les autres vues et définissez la visibilité sur disparue lorsque vous la déclarez, puis lorsque l'animation démarre comme dans le code ci-dessus, puis définissez la visibilité sur Visible et activer la vue.

J'espère que cela peut aider quelqu'un.

15
AndyRoid

Une alternative plus simple à la réponse de @ AndyRoid est d'utiliser Android:animateLayoutChanges="true" propriété. De cette façon, vous n'avez pas besoin d'écrire de code d'animation; cependant, ce n'est pas une voie à suivre si vous avez besoin d'avoir un contrôle sur l'animation.

Vous devez toujours créer un OnClickListener:

class CardTapListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        View someView = v.findViewById(R.id.view_to_expand);

        if (someView.getVisibility() == View.GONE) {
            someView.setVisibility(View.VISIBLE);
        }
        else if (someView.getVisibility() == View.VISIBLE){
            someView.setVisibility(View.GONE);
        }

    }
}

Attachez-le à chaque ViewHolder:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_holder_layout, viewGroup, false);
    v.setOnClickListener(new CardTapListener());
    return new ItemViewHolder(v);
}

N'oubliez pas de réduire les vues lors de la liaison d'un nouvel élément:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
    ...
    // Collapse (probably opened by user previously) view
    ItemViewHolder itemHolder = (ItemViewHolder) viewHolder;
    itemHolder.description.setVisibility(View.GONE);
    ...

}

view_holder_layout.xml:

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:animateLayoutChanges="true"
    Android:orientation="vertical">

 ...

    <AnyViewHere
        Android:visibility="gone"
        Android:id="@+id/view_to_expand" />

 </LinearLayout>
4
Max Malysh