RecyclerView espande / comprimi elementi


145

Voglio espandere / comprimere gli articoli del mio recyclerView per mostrare più informazioni. Voglio ottenere lo stesso effetto di SlideExpandableListView .

Fondamentalmente nella mia vista, ho una vista che non è visibile e voglio fare un'animazione uniforme di espansione / compressione piuttosto che impostare la visibilità solo su VISIBILE / ANDATO. Ho solo bisogno di espandere un oggetto alla volta e sarebbe bello avere un po 'di elevazione per mostrare che l'oggetto è selezionato.

È lo stesso effetto del nuovo elenco della cronologia delle chiamate recenti di Android. Le opzioni "RICHIAMA INDIETRO" e "DETTAGLI" sono visibili solo quando si seleziona un oggetto.

RecyclerView articoli espandibili


Ho una domanda in merito. Nell'app Orologio, l'attività della sveglia ha una funzione simile. È fatto allo stesso modo?
user2731584

Ehi hai la soluzione? Sto anche cercando la stessa soluzione per la mia app.
Arpit Patel,

Hai trovato una soluzione?
Armin Ghoreishi,

1
Ho aggiornato il modo consigliato di farlo secondo l'I / O di Google 2016. Vedi la mia risposta stackoverflow.com/questions/27203817/…
Heisenberg,

controlla la mia risposta qui una soluzione semplice e interessante stackoverflow.com/a/48092441/5962715
Kiran Benny Joseph

Risposte:


192

Si prega di non utilizzare alcuna libreria per questo effetto, ma utilizzare il modo consigliato di farlo secondo l'I / O di Google. Nel metodo onBindViewHolder di recyclerView , procedere come segue:

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();
    }
});
  • Dove i dettagli sono i miei punti di vista che verranno visualizzati al tatto (i dettagli delle chiamate nel tuo caso. Visibilità predefinita. ANDATO).
  • mExpandedPosition è una variabile int inizializzata su -1

E per i fantastici effetti desiderati, utilizzali come attributi list_item:

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

dove comment_background è:

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

e comment_selection è:

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

22
Quando si utilizza questo codice, espandere-animazione sembra strano. Ogni volta che l'elemento in alto scompare e tutto si sposta di una posizione. Hai mai provato qualcosa di simile?
chris-pollux,

6
Provo a fare l'animazione ma lo implemento sull'adattatore, ma quale sarebbe la soluzione TransitionManager.beginDelayedTransition(recyclerView);se non potessi ottenere il riferimento alla vista del riciclatore.
Martín Serrano,

2
@Ranveer Funziona in qualche modo. Ho due RecyclerView simili, ma funziona correttamente solo per una. Non ho idea del perché. @ MartínDaniel Devi passare recyclerViewcome parametro nel costruttore per l'adattatore
chris-pollux

26
Questo è un approccio terribile. Non riesco a credere che sia stato consigliato su I / O di Google. Anche dopo aver esaminato il progetto Plaid e aver implementato tutte le soluzioni necessarie, l'animazione continua a causare alcuni importanti problemi in RecyclerView, ad esempio il primo / ultimo elemento visibile che scompare prematuramente. Anche lo scorrimento mentre l'animazione viene eseguita fa un casino di tutte le cose. In generale, non penso che risolvere tutti i problemi causati da questo approccio possa essere chiamato "basta mettere una riga e tutto funzionerà" come pubblicizzato.
Vitali Olshevski,

6
Abbiamo un modo più semplice e fresco nel 2019 per questo problema?
Ponomarenko Oleh,

76

Per questo, servivano solo linee semplici non complicate

nel tuo metodo onBindViewHolder aggiungi il codice seguente

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 è una variabile globale int inizializzata su -1

Per coloro che desiderano espandere solo un elemento e altri vengono compressi. Usa questo

per prima cosa dichiarare una variabile globale con previousExpandedPosition = -1

poi

    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);
        }
    });

Fatto!!!. Semplice e umile .. :)


ottima soluzione. Consiglio anche di spostare l'impostazione OnClickListeners onCreateViewHolderinvece dionBindViewHolder
YTerle il

1
Funziona molto bene, a proposito del tempo c'era una soluzione decente che lascia semplicemente RecyclerViewfare il lavoro, intendo, qual è il punto del LayoutManagercontrario se non gestisce i layout! Questa soluzione è migliore della soluzione più votata in quanto ha meno codice, consente di RecyclerViewgestire le cose e funziona meglio!
Mark Keen,

1
non ho capito bene come aggiungere la vista "dettagli". Dovrebbe essere statico per ciascun titolare? Cosa succede se per ogni elemento dell'elenco devo aggiungere viste diverse?
BekaBot,

@BekaBot è la vista che vuoi nascondere durante il crollo dell'elemento
Kiran Benny Joseph,

@KiranBennyJoseph sì, ho capito. In questo caso la vista dovrebbe essere la stessa per tutti gli articoli? Cosa succede se desidero visualizzazioni diverse per elementi diversi?
BekaBot,

72

Non dire che questo è l'approccio migliore, ma sembra funzionare per me.

Il codice completo è disponibile all'indirizzo: Esempio di codice su: https://github.com/dbleicher/recyclerview-grid-quickreturn

Prima di tutto, aggiungi l'area espansa al layout della cella / elemento e rendi animateLayoutChanges = "true" il layout della cella racchiuso. Ciò assicurerà che l'espansione / compressione sia animata:

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

Quindi, fai in modo che la tua classe RV Adapter implementi View.OnClickListener in modo da poter agire sull'elemento su cui fai clic. Aggiungi un campo int per mantenere la posizione di una vista espansa e inizializzalo su un valore negativo:

private int expandedPosition = -1;

Infine, implementa i metodi ViewHolder, onBindViewHolder () e sovrascrivi il metodo onClick (). Espanderete la vista in onBindViewHolder se la sua posizione è uguale a "extendedPosition" e, in caso contrario, la nasconderete. Puoi impostare il valore di extendedPosition nel listener 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);
    }
}

Questo dovrebbe espandere solo un elemento alla volta, utilizzando l'animazione predefinita di sistema per la modifica del layout. Almeno funziona per me. Spero che sia d'aiuto.


So come mantenere solo un oggetto selezionato. Non so davvero come fare l'animazione su quell'elemento. L'animazione di espansione / compressione con l'animazione di sistema predefinita non sembra molto fluida.
Stanete

1
Non ho ancora provato quanto segue, ma sembra che funzionerà. Controlla la risposta a: stackoverflow.com/a/26443762/2259418
MojoTosh

2
@ user2731584 - Non credo. Guardando (quello che credo sia) la loro fonte, sembra che l'orologio Lollipop stia usando un ListView per visualizzare l'elenco degli allarmi. Layout: android.googlesource.com/platform/packages/apps/DeskClock/+/… Sembrano avere un codice personalizzato per animare gli elementi di espansione / compressione in questo elenco. Vedi la seguente fonte: android.googlesource.com/platform/packages/apps/DeskClock/+/…
MojoTosh

1
@MojoTosh hai ragione. Stanno usando ListView e stanno facendo l'animazione usando il codice. expandAlarmla funzione nei AlarmClockFragment.javafile esegue la parte di espansione.
user2731584

4
Quale onClick()dovrei scavalcare? Non c'è onClicknell'adattatore.
Vicky Leong,

15

Esiste una libreria molto semplice da usare con supporto gradle: https://github.com/cachapa/ExpandableLayout .

Direttamente dai documenti della biblioteca:

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

Dopo aver contrassegnato le vostre espandibili di vista, basta chiamare uno di questi metodi sul contenitore: expand(), collapse()otoggle()


È ancora il modo migliore per farlo? Sto cercando di seguire quello che hai scritto. Ho alcune viste di riciclo che voglio espandere per mostrare un grafico quando si fa clic su
sourlemonaid

10

So che è passato molto tempo da quando è stata pubblicata la domanda originale. Ma penso che per quelli lenti come me una spiegazione della risposta di @ Heisenberg sarebbe di aiuto.

Dichiarare due variabili nella classe adattatore come

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

Quindi in onBindViewHolder seguendo come indicato nella risposta originale.

      // 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();
            }
        });

E infine per ottenere l'oggetto recyclerView nella sostituzione dell'adattatore

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

    this.recyclerView = recyclerView;
}

Spero che questo ti aiuti.


3
Ottima e semplice soluzione. Piccolo miglioramento, usa RecyclerView.NO_POSITION anziché il numero magico -1.
Casper Bang,

8

Semplicemente non è necessario utilizzare librerie di terze parti. Un piccolo trucco nel metodo dimostrato in Google I / O 2016 e Heisenberg su questo argomento, fa il trucco.

Dal momento che notifyDataSetChanged() ridisegna il completoRecyclerView , notifyDataItemChanged()è una scelta migliore (non il migliore) perché abbiamo la posizione e la ViewHoldera nostra disposizione, e notifyDataItemChanged()solo ridisegna il particolare ViewHolderin una determinata posizione .

Ma il problema è che la scomparsa prematura del ViewHolderclic e della sua comparsa non viene eliminata anche se notifyDataItemChanged()viene utilizzata.

Il codice seguente non ricorre a notifyDataSetChanged()o notifyDataItemChanged()ed è testato su API 23 e funziona come un incantesimo quando utilizzato su un RecyclerView in cui ogni ViewHolder ha un CardViewelemento radice:

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è un numero intero globale inizializzato su -1. detailsè la vista completa che viene mostrata quando espansa e occultata quando viene compressa.

Come detto, l'elemento radice di ViewHolderè un CardViewcon foregrounde stateListAnimatorattributi definiti esattamente come detto da Heisenberg su questo argomento.

AGGIORNAMENTO: la dimostrazione precedente comprimerà l'elemento espanso in precedenza se uno di essi viene espanso. Per modificare questo comportamento e mantenere un elemento espanso così com'è anche quando viene espanso un altro elemento, è necessario il seguente codice.

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);

AGGIORNAMENTO: quando si espandono gli ultimi elementi dell'elenco, potrebbe non essere portato alla piena visibilità perché la parte espansa va sotto lo schermo. Per visualizzare l'intero elemento sullo schermo, utilizzare il seguente codice.

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);

IMPORTANTE: affinché le dimostrazioni di cui sopra funzionino, è necessario conservare nel proprio codice un'istanza di RecyclerView ed è LayoutManager (la versione successiva per flessibilità)


Grazie questa soluzione funziona per me. Cerco di evitare di usarlo notifyItemChangedperché ho un'immagine ImageViewche carica un'immagine da un URL. notifyItemChangedricaricare la mia immagine rende strano
Tam Huynh,

La linea che lo inchioda è TransitionManager.beginDelayedTransition(recycler);, grande scoperta. Ma ho scoperto che usando questo metodo, se faccio clic in sequenza su più righe di spam, alla fine si innesca un arresto interno The specified child already has a parent. You must call removeView() on the child's parent first. Immagino che ciò sia dovuto al riciclaggio della vista sui limiti della vista del riciclatore, ma non posso dirlo con certezza. Qualcuno ha avuto lo stesso problema?
Roger Oba,

È ancora il modo migliore per farlo? Sto cercando di seguire quello che hai scritto. Ho alcune viste di riciclo che voglio espandere per mostrare un grafico quando si fa clic su. Sto facendo fatica a capire esattamente cosa fare
sourlemonaid,

Qualcuno ha l'esempio completo di questa implementazione? Intendo un esempio di codice funzionante. Per favore aiuto. Non riesco a capire come farlo?
Munazza,

7

Dopo aver utilizzato il modo consigliato di implementare oggetti espandibili / comprimibili che risiedono in un oggetto Espandi / comprimiRecyclerView su RecyclerView con risposta di HeisenBerg , ho visto alcuni artefatti evidenti ogni volta che RecyclerViewvengono aggiornati invocando TransitionManager.beginDelayedTransition(ViewGroup)e successivamente notifyDatasetChanged().

La sua risposta 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();
    }
});

Modificato:

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());
    }
}
  • i dettagli sono vista che si desidera mostrare / nascondere durante l'espansione / compressione dell'elemento
  • mExpandedPosition è un oggetto intche tiene traccia dell'elemento espanso
  • mExpandedHolder è ViewHolderusato durante il collasso degli oggetti

Si noti che il metodo TransitionManager.beginDelayedTransition(ViewGroup)e notifyDataSetChanged()sono sostituiti da notifyItemChanged(int)target specifico e alcune piccole modifiche.

Dopo la modifica, i precedenti effetti indesiderati dovrebbero essere spariti. Tuttavia, questa potrebbe non essere la soluzione perfetta. Ha fatto solo quello che volevo, eliminando i pori.

::MODIFICARE::

Per chiarimenti, entrambi mExpandedPositione mExpandedHoldersono globali.


Spiegare come e dove mExpandedHolder viene dichiarato e utilizzato?
Werner,

1
@Werner Ho modificato la risposta per mostrare dove è stata dichiarata. L'uso è all'interno dello snippet stesso e lo scopo. Viene utilizzato per animare la compressione, elemento espanso.
Chan Teck Wei,

Adoro questo approccio soprattutto per quanto riguarda le animazioni, ma sto facendo questa piccola "dissolvenza" quando si fa clic sull'elemento. Hai detto anche questo o diversamente, questo è dovuto all'uso di notifyItemChanged ()? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/…
kazume

Sì. Come hai indovinato, è causato da notifyItemChanged(). Puoi animare e modificare manualmente l'altezza dell'elemento e aggiungere visualizzazioni al suo interno.
Chan Teck Wei,

@ChanTeckWei: la tua soluzione funziona benissimo ma sfarfallio dell'immagine di riga ogni volta che comprimo o esplodo la riga dell'elemento di riciclaggio .. C'è qualche soluzione per questo?
Pragya Mendiratta,

3

Effettuare quanto segue dopo aver impostato il listener onClick sulla 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();
    }
}

Penso che dovrebbe aiutare, è così che ho implementato e fa lo stesso google nella vista delle chiamate recenti.


2

Sono sorpreso che non ci sia ancora una risposta concisa, sebbene una simile animazione di espansione / compressione sia molto facile da ottenere con solo 2 righe di codice:

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

insieme a

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

Quindi, per me, le spiegazioni nel link qui sotto sono state davvero utili: https://medium.com/@nikola.jakshic/how-to-expand-collapse-items-in-recyclerview-49a648a403a6


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);
        }
}

inserisci qui la descrizione dell'immagine


0

Usa due tipi di visualizzazione nel tuo RVAdapter. Uno per il layout espanso e l'altro per il collasso. E la magia accade con l'impostazione android:animateLayoutChanges="true"per RecyclerView Checkout l'effetto ottenuto usando questo a 0:42 in questo video


ti dispiace spiegarlo meglio? Non riesco a farlo funzionare
sourlemonaid

@sourlemonaid fondamentalmente crei più tipi di vista per l'elenco come spiegato in stackoverflow.com/a/26245463/3731795 ... Tieni una traccia dell'indice per il quale l'elemento viene espanso e il resto degli oggetti viene compresso in quel momento . Ora if (current_item_index == extended_item_index) {return VIEW_TYPE_EXPANDED} else {reutrn VIEW_TYPE_COLLAPSED}
penduDev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.