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 .
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.
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.
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>