RecyclerAfficher les éléments développer / réduire

145

Je souhaite développer / réduire les éléments de mon recyclerView afin d'afficher plus d'informations. Je veux obtenir le même effet de la SlideExpandableListView .

Fondamentalement, dans mon viewHolder, j'ai une vue qui n'est pas visible et je veux faire une animation de développement / réduction fluide plutôt que de définir la visibilité sur VISIBLE / GONE uniquement. Je n'ai besoin que d'un élément à développer à la fois et ce serait cool d'avoir une certaine élévation pour montrer que l'élément est sélectionné.

C'est le même effet de la nouvelle liste d'historique des appels récents Android. Les options «RAPPEL» et «DÉTAILS» ne sont visibles que lorsqu'un élément est sélectionné.

RecyclerVoir les articles extensibles

Stanete
la source
J'ai une question connexe. Dans l'application Horloge, l'activité des réglages d'alarme a une fonctionnalité similaire. Est-ce fait de la même manière?
user2731584
Hé, avez-vous la solution? je recherche également la même solution pour mon application.
Arpit Patel
Avez-vous trouvé une solution?
Armin Ghoreishi
1
J'ai mis à jour la méthode recommandée pour le faire selon Google I / O 2016. Voir ma réponse stackoverflow.com/questions/27203817/…
Heisenberg
vérifiez ma réponse ici une solution simple et cool stackoverflow.com/a/48092441/5962715
Kiran Benny Joseph

Réponses:

192

Veuillez n'utiliser aucune bibliothèque pour cet effet à la place, utilisez la méthode recommandée pour le faire selon Google I / O. Dans la méthode onBindViewHolder de votre recyclerView, procédez comme suit :

final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mExpandedPosition = isExpanded ? -1:position;
        TransitionManager.beginDelayedTransition(recyclerView);
        notifyDataSetChanged();
    }
});
  • Où les détails sont ma vue qui sera affichée au toucher (détails de l'appel dans votre cas. Visibilité par défaut.GONE).
  • mExpandedPosition est une variable int initialisée à -1

Et pour les effets sympas que vous vouliez, utilisez-les comme attributs list_item:

android:background="@drawable/comment_background"
android:stateListAnimator="@animator/comment_selection"

où comment_background est:

<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true"
android:enterFadeDuration="@android:integer/config_shortAnimTime"
android:exitFadeDuration="@android:integer/config_shortAnimTime">

<item android:state_activated="true" android:drawable="@color/selected_comment_background" />
<item android:drawable="@color/comment_background" />
</selector>

et comment_selection est:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_activated="true">
    <objectAnimator
        android:propertyName="translationZ"
        android:valueTo="@dimen/z_card"
        android:duration="2000"
        android:interpolator="@android:interpolator/fast_out_slow_in" />
</item>

<item>
    <objectAnimator
        android:propertyName="translationZ"
        android:valueTo="0dp"
        android:duration="2000"
        android:interpolator="@android:interpolator/fast_out_slow_in" />
</item>
</selector>
Heisenberg
la source
22
Lorsque vous utilisez ce code, l'animation d'expansion semble bizarre. Chaque fois que l'élément supérieur disparaît et que tout change d'une position. Avez-vous déjà vécu quelque chose de similaire?
chris-pollux
6
J'essaye de faire l'animation mais je l'implémente sur l'adaptateur, mais quelle serait la solution TransitionManager.beginDelayedTransition(recyclerView);si je ne peux pas avoir la référence de vue de recycleur.
Martín Serrano
2
@Ranveer Cela fonctionne en quelque sorte. J'ai deux recyclerViews assez similaires, mais cela ne fonctionne correctement que pour un. Je ne sais pas pourquoi. @ MartínDaniel Vous devez passer le en recyclerViewtant que paramètre dans le constructeur de l'adaptateur
chris-pollux
26
C'est une approche horrible. Je ne peux pas croire qu'il a été recommandé à Google I / O. Même après avoir étudié le projet Plaid et mis en œuvre toutes les solutions de contournement requises, l'animation provoque toujours des problèmes majeurs dans RecyclerView, par exemple le premier / dernier élément visible disparaissant prématurément. Le défilement pendant que l'animation s'exécute gâche tout. En général, je ne pense pas que la résolution de tous les problèmes causés par cette approche peut être appelée "juste mettre une ligne et tout fonctionnera" comme annoncé.
Vitali Olshevski
6
Avons-nous un moyen plus frais et plus simple en 2019 pour ce numéro?
Ponomarenko Oleh
76

Pour cela, juste besoin de lignes simples pas compliquées

dans votre méthode onBindViewHolder, ajoutez le code ci-dessous

final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mExpandedPosition = isExpanded ? -1:position;
        notifyItemChanged(position);
    }
});

mExpandedPosition est une variable globale int initialisée à -1

Pour ceux qui veulent qu'un seul élément soit développé et que les autres soient réduits. Utilisez ceci

déclarez d'abord une variable globale avec previousExpandedPosition = -1

puis

    final boolean isExpanded = position==mExpandedPosition;
    holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
    holder.itemView.setActivated(isExpanded);

    if (isExpanded)
       previousExpandedPosition = position;

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mExpandedPosition = isExpanded ? -1:position;
            notifyItemChanged(previousExpandedPosition);
            notifyItemChanged(position);
        }
    });

Terminé!!!. Simple et humble .. :)

Kiran Benny Joseph
la source
excellente solution. Je recommande également de déplacer les paramètres sur OnClickListenerau onCreateViewHolderlieu deonBindViewHolder
YTerle
1
Fonctionne très bien, il était temps qu'il y ait une solution décente qui laisse simplement le RecyclerViewfaire le travail, je veux dire, à quoi LayoutManagersert le sinon si elle ne gère pas les mises en page! Cette solution est meilleure que la solution la plus votée car elle a moins de code, permet de RecyclerViewgérer les choses et fonctionne mieux!
Mark Keen
1
ne comprenait pas tout à fait comment ajouter la vue «détails». Doit-il être statique pour chaque titulaire? Et si, pour chaque élément de liste, je devais ajouter des vues différentes?
BekaBot
@BekaBot c'est la vue que vous souhaitez masquer lors de la réduction de l'élément
Kiran Benny Joseph
@KiranBennyJoseph oui, je comprends. Dans ce cas, la vue doit être la même pour tous les éléments? Que faire si je veux des vues différentes pour différents éléments?
BekaBot
72

Ne pas dire que c'est la meilleure approche, mais cela semble fonctionner pour moi.

Le code complet peut être trouvé à l' adresse : Exemple de code sur: https://github.com/dbleicher/recyclerview-grid-quickreturn

Tout d'abord, ajoutez la zone développée à votre disposition de cellule / élément et rendez la disposition de cellule englobante animateLayoutChanges = "true". Cela garantira que le développement / réduction est animé:

<LinearLayout
    android:id="@+id/llCardBack"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    android:animateLayoutChanges="true"
    android:padding="4dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center|fill_horizontal"
        android:padding="10dp"
        android:gravity="center"
        android:background="@android:color/holo_green_dark"
        android:text="This is a long title to show wrapping of text in the view."
        android:textColor="@android:color/white"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tvSubTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center|fill_horizontal"
        android:background="@android:color/holo_purple"
        android:padding="6dp"
        android:text="My subtitle..."
        android:textColor="@android:color/white"
        android:textSize="12sp" />

    <LinearLayout
        android:id="@+id/llExpandArea"
        android:visibility="gone"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="6dp"
            android:text="Item One" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="6dp"
            android:text="Item Two" />

    </LinearLayout>
</LinearLayout>

Ensuite, faites en sorte que votre classe RV Adapter implémente View.OnClickListener afin que vous puissiez agir sur l'élément sur lequel l'utilisateur clique. Ajoutez un champ int pour contenir la position de la vue développée et initialisez-la à une valeur négative:

private int expandedPosition = -1;

Enfin, implémentez vos méthodes ViewHolder, onBindViewHolder () et remplacez la méthode onClick (). Vous développerez la vue dans onBindViewHolder si sa position est égale à "ExpandPosition", et vous la masquerez dans le cas contraire. Vous définissez la valeur de ExpandPosition dans l'écouteur onClick:

@Override
public void onBindViewHolder(RVAdapter.ViewHolder holder, int position) {

    int colorIndex = randy.nextInt(bgColors.length);
    holder.tvTitle.setText(mDataset.get(position));
    holder.tvTitle.setBackgroundColor(bgColors[colorIndex]);
    holder.tvSubTitle.setBackgroundColor(sbgColors[colorIndex]);

    if (position == expandedPosition) {
        holder.llExpandArea.setVisibility(View.VISIBLE);
    } else {
        holder.llExpandArea.setVisibility(View.GONE);
    }
}

@Override
public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    String theString = mDataset.get(holder.getPosition());

    // Check for an expanded view, collapse if you find one
    if (expandedPosition >= 0) {
        int prev = expandedPosition;
        notifyItemChanged(prev);
    }
    // Set the current position to "expanded"
    expandedPosition = holder.getPosition();
    notifyItemChanged(expandedPosition);

    Toast.makeText(mContext, "Clicked: "+theString, Toast.LENGTH_SHORT).show();
}

/**
 * Create a ViewHolder to represent your cell layout
 * and data element structure
 */
public static class ViewHolder extends RecyclerView.ViewHolder {
    TextView tvTitle;
    TextView tvSubTitle;
    LinearLayout llExpandArea;

    public ViewHolder(View itemView) {
        super(itemView);

        tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
        tvSubTitle = (TextView) itemView.findViewById(R.id.tvSubTitle);
        llExpandArea = (LinearLayout) itemView.findViewById(R.id.llExpandArea);
    }
}

Cela ne devrait développer qu'un seul élément à la fois, en utilisant l'animation par défaut du système pour le changement de disposition. Au moins ça marche pour moi. J'espère que ça aide.

MojoTosh
la source
Je sais comment ne garder qu'un seul élément sélectionné. Je ne sais pas vraiment comment faire l'animation sur cet élément. L'animation d'agrandissement / réduction avec l'animation système par défaut n'a pas l'air très fluide.
stanete
1
Je n'ai pas encore essayé ce qui suit, mais il semble que cela fonctionnera. Découvrez la réponse sur: stackoverflow.com/a/26443762/2259418
MojoTosh
2
@ user2731584 - Je ne pense pas. En regardant (ce que je crois être) leur source, il semble que l'horloge Lollipop utilise un ListView pour afficher la liste des alarmes. Mise en page: android.googlesource.com/platform/packages/apps/DeskClock/+/… Ils semblent avoir un code personnalisé pour animer les éléments développer / réduire dans cette liste. Voir la source suivante: android.googlesource.com/platform/packages/apps/DeskClock/+/…
MojoTosh
1
@MojoTosh vous avez raison. Ils utilisent ListView et font l'animation à l'aide de code. expandAlarmLa fonction dans les AlarmClockFragment.javafichiers exécute la partie d'extension.
user2731584
4
Lequel onClick()devrais-je remplacer? Il n'y a pas onClickdans l'adaptateur.
Vicky Leong
15

Il existe une bibliothèque très simple à utiliser avec le support de gradle: https://github.com/cachapa/ExpandableLayout .

Directement à partir de la documentation de la bibliothèque:

<net.cachapa.expandablelayout.ExpandableLinearLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:el_duration="1000"
    app:el_expanded="true">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Click here to toggle expansion" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="Fixed height"
        app:layout_expandable="true" />

 </net.cachapa.expandablelayout.ExpandableLinearLayout>

Une fois que vous marquez votre extensible vues, il suffit d' appeler une de ces méthodes sur le contenant: expand(), collapse()outoggle()

Laurențiu Onac
la source
Est-ce toujours la meilleure façon de procéder? J'essaye de suivre ce que vous avez écrit. J'ai quelques vues de recyclage que je souhaite développer pour afficher un graphique lorsque vous cliquez dessus
sourlemonaid
10

Je sais que cela fait longtemps que la question initiale a été publiée. Mais je pense que pour les lents comme moi, une explication de la réponse de @ Heisenberg serait utile.

Déclarez deux variables dans la classe d'adaptateur comme

private int mExpandedPosition= -1;
private RecyclerView recyclerView = null;

Puis dans onBindViewHolder suivant comme indiqué dans la réponse d'origine.

      // This line checks if the item displayed on screen 
      // was expanded or not (Remembering the fact that Recycler View )
      // reuses views so onBindViewHolder will be called for all
      // items visible on screen.
    final boolean isExpanded = position==mExpandedPosition;

        //This line hides or shows the layout in question
        holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);

        // I do not know what the heck this is :)
        holder.itemView.setActivated(isExpanded);

        // Click event for each item (itemView is an in-built variable of holder class)
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

 // if the clicked item is already expaned then return -1 
//else return the position (this works with notifyDatasetchanged )
                mExpandedPosition = isExpanded ? -1:position;
    // fancy animations can skip if like
                TransitionManager.beginDelayedTransition(recyclerView);
    //This will call the onBindViewHolder for all the itemViews on Screen
                notifyDataSetChanged();
            }
        });

Et enfin pour obtenir l'objet recyclerView dans le remplacement de l'adaptateur

@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);

    this.recyclerView = recyclerView;
}

J'espère que cela t'aides.

cul de shahroz
la source
3
Solution géniale et simple. Petite amélioration, utilisez RecyclerView.NO_POSITION plutôt que le nombre magique -1.
Casper Bang
8

Il n'est tout simplement pas nécessaire d'utiliser des bibliothèques tierces. Un petit tweak dans la méthode démontrée dans Google I / O 2016 et Heisenberg sur ce sujet, fait l'affaire.

Depuis notifyDataSetChanged() redessine le completRecyclerView , notifyDataItemChanged()est une meilleure option (pas la meilleure) car nous avons la position et le ViewHolderà notre disposition, et notifyDataItemChanged()seulement redessine le particulier ViewHolderà une position donnée .

Mais le problème est que la disparition prématurée du ViewHolder clic et son émergence n'est pas éliminée même si elle notifyDataItemChanged()est utilisée.

Le code suivant ne recourt pas à notifyDataSetChanged()ou notifyDataItemChanged()et est testé sur l'API 23 et fonctionne comme un charme lorsqu'il est utilisé sur un RecyclerView où chaque ViewHolder a un CardViewélément racine:

holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final boolean visibility = holder.details.getVisibility()==View.VISIBLE;

            if (!visibility)
            {
                holder.itemView.setActivated(true);
                holder.details.setVisibility(View.VISIBLE);
                if (prev_expanded!=-1 && prev_expanded!=position)
                {
                    recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.setActivated(false);
                    recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.findViewById(R.id.cpl_details).setVisibility(View.GONE);
                }
                prev_expanded = position;
            }
            else
            {
                holder.itemView.setActivated(false);
                holder.details.setVisibility(View.GONE);
            }
            TransitionManager.beginDelayedTransition(recycler);              
        }
});

prev_position est un entier global initialisé à -1. detailsest la vue complète qui est affichée lorsqu'elle est développée et masquée lorsqu'elle est réduite.

Comme dit, l'élément racine de ViewHolderest un CardViewavec foregroundet des stateListAnimatorattributs définis exactement comme l'a dit Heisenberg sur ce sujet.

MISE À JOUR: La démonstration ci-dessus réduira l'élément déjà développé si l'un d'entre eux est développé. Pour modifier ce comportement et conserver un élément développé tel quel, même lorsqu'un autre élément est développé, vous aurez besoin du code suivant.

if (row.details.getVisibility()!=View.VISIBLE)
    {
        row.details.setVisibility(View.VISIBLE);
        row.root.setActivated(true);
        row.details.animate().alpha(1).setStartDelay(500);
    }
    else
    {
        row.root.setActivated(false);
        row.details.setVisibility(View.GONE);
        row.details.setAlpha(0);
    }
    TransitionManager.beginDelayedTransition(recycler);

MISE À JOUR: Lorsque vous développez les derniers éléments de la liste, il se peut que la visibilité totale ne soit pas visible car la partie développée passe sous l'écran. Pour obtenir l'élément complet dans l'écran, utilisez le code suivant.

LinearLayoutManager manager = (LinearLayoutManager) recycler.getLayoutManager();
    int distance;
    View first = recycler.getChildAt(0);
    int height = first.getHeight();
    int current = recycler.getChildAdapterPosition(first);
    int p = Math.abs(position - current);
    if (p > 5) distance = (p - (p - 5)) * height;
    else       distance = p * height;
    manager.scrollToPositionWithOffset(position, distance);

IMPORTANT: pour que les démonstrations ci-dessus fonctionnent, il faut conserver dans leur code une instance de RecyclerView et de son LayoutManager (le plus récent pour plus de flexibilité)

Koushik Shom Choudhury
la source
Merci cette solution fonctionne pour moi. J'essaie d'éviter d'utiliser notifyItemChangedparce que j'ai une ImageViewimage qui charge à partir d'une URL. notifyItemChangedrecharger mon image le rend bizarre
Tam Huynh
La ligne qui cloue, c'est une TransitionManager.beginDelayedTransition(recycler);excellente trouvaille. Mais j'ai découvert qu'en utilisant cette méthode, si je clique sur plusieurs lignes de manière séquentielle, cela déclenche finalement un crash interne The specified child already has a parent. You must call removeView() on the child's parent first. J'imagine que cela est dû au recyclage de la vue sur les limites de la vue des recycleurs, mais je ne peux pas le dire avec certitude. Quelqu'un a-t-il eu le même problème?
Roger Oba
Est-ce toujours la meilleure façon de procéder? J'essaye de suivre ce que vous avez écrit. J'ai des vues de recyclage que je souhaite développer pour afficher un graphique lorsque vous cliquez dessus. J'ai du mal à comprendre exactement quoi faire
sourlemonaid
Quelqu'un a-t-il l'exemple complet de cette implémentation? Je veux dire un exemple de code de travail. Veuillez aider. Je suis incapable de comprendre comment faire?
Munazza le
7

Après avoir utilisé la méthode recommandée pour implémenter des éléments extensibles / réductibles résidant dans des éléments de développement / réductionRecyclerView sur RecyclerView auxquels HeisenBerg a répondu , j'ai vu des artefacts visibles chaque fois que le RecyclerViewest actualisé en appelant TransitionManager.beginDelayedTransition(ViewGroup)et par la suite notifyDatasetChanged().

Sa réponse originale:

final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mExpandedPosition = isExpanded ? -1 : position;
        TransitionManager.beginDelayedTransition(recyclerView);
        notifyDataSetChanged();
    }
});

Modifié:

final boolean isExpanded = position == mExpandedPosition;
holder.details.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
holder.view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mExpandedHolder != null) {
            mExpandedHolder.details.setVisibility(View.GONE);
            notifyItemChanged(mExpandedPosition);
        }
        mExpandedPosition = isExpanded ? -1 : holder.getAdapterPosition();
        mExpandedHolder = isExpanded ? null : holder;
        notifyItemChanged(holder.getAdapterPosition());
    }
}
  • les détails sont la vue que vous souhaitez afficher / masquer pendant le développement / la réduction de l'élément
  • mExpandedPosition est un intqui garde une trace de l'élément développé
  • mExpandedHolder est ViewHolderutilisé lors de la réduction de l' élément

Notez que la méthode TransitionManager.beginDelayedTransition(ViewGroup)et notifyDataSetChanged()sont remplacés par notifyItemChanged(int)pour cibler un élément spécifique et quelques petites modifications.

Après la modification, les effets indésirables précédents devraient disparaître. Cependant, ce n'est peut-être pas la solution parfaite. Il n'a fait que ce que je voulais, éliminant les horreurs.

::ÉDITER::

Pour clarification, les deux mExpandedPositionet mExpandedHoldersont globaux.

Chan Teck Wei
la source
Veuillez expliquer comment et où mExpandedHolder est déclaré et utilisé?
Werner
1
@Werner J'ai édité la réponse pour montrer où elle est déclarée. L'utilisation est dans l'extrait lui-même ainsi que le but. Il est utilisé pour animer un élément agrandi et réduit.
Chan Teck Wei
J'adore cette approche en ce qui concerne les animations, mais j'ai ce petit "fondu" en cliquant sur l'élément. Avez-vous cela aussi ou différemment, est-ce dû à l'utilisation de notifyItemChanged ()? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/…
kazume
Oui. Comme vous l'avez deviné, il est causé par notifyItemChanged(). Vous pouvez animer et modifier manuellement la hauteur de l'élément et y ajouter des vues.
Chan Teck Wei
@ChanTeckWei: votre solution fonctionne bien mais l'image de la ligne scintille chaque fois que je réduis ou que j'élargis la ligne de l'élément recyclerview..Y a-t-il une solution pour cela?
Pragya Mendiratta
3

Procédez comme suit après avoir défini l'écouteur onClick sur la classe ViewHolder:

@Override
    public void onClick(View v) {
        final int originalHeight = yourLinearLayout.getHeight();
        animationDown(YourLinearLayout, originalHeight);//here put the name of you layout that have the options to expand.
    }

    //Animation for devices with kitkat and below
    public void animationDown(LinearLayout billChoices, int originalHeight){

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

            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) {
                    billChoices.setVisibility(View.INVISIBLE);
                    billChoices.setEnabled(false);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

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


        valueAnimator.start();
    }
}

Je pense que cela devrait aider, c'est ainsi que j'ai mis en œuvre et fait la même chose que Google fait dans la vue des appels récents.

Rensodarwin
la source
2

Je suis surpris qu'il n'y ait pas encore de réponse concise, bien qu'une telle animation d'expansion / réduction soit très facile à réaliser avec seulement 2 lignes de code:

(recycler.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false // called once

ensemble avec

notifyItemChanged(position) // in adapter, whenever a child view in item's recycler gets hidden/shown

Donc pour moi, les explications dans le lien ci-dessous étaient vraiment utiles: https://medium.com/@nikola.jakshic/how-to-expand-collapse-items-in-recyclerview-49a648a403a6

Bianca Daniciuc
la source
1
//Global Variable

private int selectedPosition = -1;

 @Override
    public void onBindViewHolder(final CustomViewHolder customViewHolder, final int i) {

        final int position = i;
        final GetProductCatalouge.details feedItem = this.postBeanses.get(i);
        customViewHolder.lly_main.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectedPosition = i;
                notifyDataSetChanged();
            }
        });
        if (selectedPosition == i) {

          if (customViewHolder.lly_hsn_code.getVisibility() == View.VISIBLE) {

            customViewHolder.lly_hsn_code.setVisibility(View.GONE);
            customViewHolder.lly_sole.setVisibility(View.GONE);
            customViewHolder.lly_sole_material.setVisibility(View.GONE);

        } else {

            customViewHolder.lly_hsn_code.setVisibility(View.VISIBLE);
            customViewHolder.lly_sole.setVisibility(View.VISIBLE);
            customViewHolder.lly_sole_material.setVisibility(View.VISIBLE);
        }


        } else {
            customViewHolder.lly_hsn_code.setVisibility(View.GONE);
            customViewHolder.lly_sole.setVisibility(View.GONE);
            customViewHolder.lly_sole_material.setVisibility(View.GONE);
        }
}

entrez la description de l'image ici

Keshav Gera
la source
0

Utilisez deux types de vue dans votre RVAdapter. Un pour la mise en page étendue et un autre pour la mise en page réduite. Et la magie opère avec le réglage android:animateLayoutChanges="true"de RecyclerView Checkout l'effet obtenu en utilisant ceci à 0:42 dans cette vidéo

penduDev
la source
l'esprit d'expliquer cela mieux? Je n'arrive pas à le faire fonctionner
sourlemonaid
@sourlemonaid en gros, vous créez plusieurs types de vues pour la liste comme expliqué dans stackoverflow.com/a/26245463/3731795 ... Vous gardez une trace de l'index pour lequel l'élément est développé, et le reste des éléments est réduit à ce moment . Now if (current_item_index == extended_item_index) {return VIEW_TYPE_EXPANDED} else {reutrn VIEW_TYPE_COLLAPSED}
penduDev