RecyclerView Elemente erweitern / reduzieren

145

Ich möchte die Elemente meiner recyclerView erweitern / reduzieren, um weitere Informationen anzuzeigen. Ich möchte den gleichen Effekt wie SlideExpandableListView erzielen .

Grundsätzlich habe ich in meinem viewHolder eine Ansicht, die nicht sichtbar ist, und ich möchte eine reibungslose Animation zum Erweitern / Reduzieren erstellen, anstatt die Sichtbarkeit nur auf SICHTBAR / GEGANGEN zu setzen. Ich brauche immer nur ein Element, das gleichzeitig erweitert werden soll, und es wäre cool, eine gewisse Höhe zu haben, um zu zeigen, dass das Element ausgewählt ist.

Dies ist der gleiche Effekt wie in der neuen Liste der letzten Anrufe in Android. Die Optionen "CALL BACK" und "DETAILS" sind nur sichtbar, wenn ein Element ausgewählt ist.

Erweiterbare RecyclerView-Elemente

stanete
quelle
Ich habe eine verwandte Frage. In der Uhr-App hat die Alarmeinstellung eine ähnliche Funktion. Wird es genauso gemacht?
user2731584
Hey, hast du die Lösung? Ich suche auch nach der gleichen Lösung für meine App.
Arpit Patel
Haben Sie eine Lösung gefunden?
Armin Ghoreishi
1
Ich habe die empfohlene Vorgehensweise gemäß Google I / O 2016 aktualisiert. Siehe meine Antwort stackoverflow.com/questions/27203817/…
Heisenberg
Überprüfen Sie meine Antwort hier eine einfache und coole Lösung stackoverflow.com/a/48092441/5962715
Kiran Benny Joseph

Antworten:

192

Verwenden Sie für diesen Effekt keine Bibliothek, sondern verwenden Sie die empfohlene Methode gemäß Google I / O. Gehen Sie in der onBindViewHolder- Methode Ihres recyclerView folgendermaßen vor :

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();
    }
});
  • Wo Details meine Ansicht ist, die bei Berührung angezeigt wird (Anrufdetails in Ihrem Fall. Standard-Sichtbarkeit. GEGANGEN).
  • mExpandedPosition ist eine mit -1 initialisierte int-Variable

Und für die coolen Effekte, die Sie wollten, verwenden Sie diese als Ihre list_item-Attribute:

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

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

und comment_selection ist:

<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
quelle
22
Bei Verwendung dieses Codes sieht die Erweiterungsanimation seltsam aus. Jedes Mal, wenn das oberste Element verschwindet und sich alles um eine Position verschiebt. Haben Sie jemals etwas Ähnliches erlebt?
Chris-Pollux
6
Ich versuche, die Animation zu erstellen, aber ich implementiere dies auf dem Adapter, aber was wäre die Lösung für das TransitionManager.beginDelayedTransition(recyclerView);Problem, wenn ich die Referenz für die Recycler-Ansicht nicht verwenden kann.
Martín Serrano
2
@ Ranveer Es funktioniert irgendwie. Ich habe zwei ziemlich ähnliche recyclerViews, aber es funktioniert nur für eine richtig. Keine Ahnung warum. @ MartínDaniel Sie müssen das recyclerViewals Parameter im Konstruktor für den Adapter übergeben
chris-pollux
26
Dies ist ein schrecklicher Ansatz. Ich kann nicht glauben, dass es bei Google I / O empfohlen wurde. Selbst nachdem das Plaid-Projekt untersucht und alle erforderlichen Problemumgehungen implementiert wurden, verursacht die Animation einige wichtige Störungen in RecyclerView, z. B. das erste / letzte sichtbare Element, das vorzeitig verschwindet. Auch das Scrollen, während die Animation läuft, bringt alles durcheinander. Im Allgemeinen denke ich nicht, dass die Behebung aller durch diesen Ansatz verursachten Probleme als "nur eine Zeile setzen und alles wird einfach funktionieren" bezeichnet werden kann.
Vitali
6
Haben wir 2019 einen frischeren und einfacheren Weg für diese Ausgabe?
Ponomarenko Oleh
76

Dafür brauchte man nur einfache Zeilen, die nicht kompliziert waren

Fügen Sie in Ihrer onBindViewHolder-Methode den folgenden Code hinzu

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 ist eine globale Variable int, die mit -1 initialisiert ist

Für diejenigen, die nur ein Element erweitern und andere reduzieren möchten. Benutze das

Deklarieren Sie zuerst eine globale Variable mit previousExpandedPosition = -1

dann

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

Getan!!!. Einfach und bescheiden .. :)

Kiran Benny Joseph
quelle
tolle Lösung. Außerdem würde ich empfehlen, die Einstellung OnClickListeners auf onCreateViewHolderanstelle vononBindViewHolder
YTerle
1
Funktioniert sehr gut, mit der Zeit gab es eine anständige Lösung, mit der RecyclerViewnur die Arbeit erledigt werden kann. Ich meine, was bringt es LayoutManagersonst, wenn die Layouts nicht verwaltet werden ? Diese Lösung ist besser als die am besten gewählte Lösung, da sie weniger Code enthält, die RecyclerViewDinge handhaben lässt und besser funktioniert!
Mark Keen
1
Ich habe nicht ganz verstanden, wie man die Ansicht "Details" hinzufügt. Sollte es für jeden Halter statisch sein? Was ist, wenn ich für jedes Listenelement unterschiedliche Ansichten hinzufügen muss?
BekaBot
@BekaBot es ist die Ansicht, die Sie während des Zusammenbruchs Gegenstand verstecken möchten
Kiran Benny Joseph
@ KiranBennyJoseph ja, ich verstehe. In diesem Fall sollte die Ansicht für alle Elemente gleich sein? Was ist, wenn ich unterschiedliche Ansichten für unterschiedliche Elemente möchte?
BekaBot
72

Nicht zu sagen, dass dies der beste Ansatz ist, aber es scheint für mich zu funktionieren.

Den vollständigen Code finden Sie unter: Beispielcode unter: https://github.com/dbleicher/recyclerview-grid-quickreturn

Fügen Sie zunächst den erweiterten Bereich zu Ihrem Zellen- / Elementlayout hinzu und machen Sie das umschließende Zellenlayout animateLayoutChanges = "true". Dadurch wird sichergestellt, dass das Erweitern / Reduzieren animiert wird:

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

Lassen Sie dann Ihre RV-Adapterklasse View.OnClickListener implementieren, damit Sie auf das angeklickte Element reagieren können. Fügen Sie ein int-Feld hinzu, um die Position der einen erweiterten Ansicht zu halten, und initialisieren Sie sie auf einen negativen Wert:

private int expandedPosition = -1;

Implementieren Sie abschließend Ihre ViewHolder-, onBindViewHolder () -Methoden und überschreiben Sie die onClick () -Methode. Sie erweitern die Ansicht in onBindViewHolder, wenn ihre Position gleich "expandedPosition" ist, und blenden sie aus, wenn nicht. Sie legen den Wert von expandPosition im onClick-Listener fest:

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

Dies sollte jeweils nur ein Element erweitern und die Systemstandardanimation für die Layoutänderung verwenden. Zumindest funktioniert es bei mir. Ich hoffe es hilft.

MojoTosh
quelle
Ich weiß, wie man nur einen Artikel ausgewählt hält. Ich weiß nicht wirklich, wie ich die Animation für diesen Gegenstand machen soll. Die Erweiterungs- / Reduzierungsanimation mit der Standardsystemanimation sieht nicht sehr flüssig aus.
Stanete
1
Ich habe Folgendes noch nicht ausprobiert, aber es sieht sicher so aus, als würde es funktionieren. Überprüfen Sie die Antwort auf: stackoverflow.com/a/26443762/2259418
MojoTosh
2
@ user2731584 - Das glaube ich nicht. Wenn man sich ihre Quelle ansieht (was ich glaube), scheint es, dass die Lollipop-Uhr eine ListView verwendet, um die Liste der Alarme anzuzeigen. Layout: android.googlesource.com/platform/packages/apps/DeskClock/+/… Sie scheinen benutzerdefinierten Code zum Animieren der Elemente zum Erweitern / Reduzieren in dieser Liste zu haben. Siehe die folgende Quelle: android.googlesource.com/platform/packages/apps/DeskClock/+/…
MojoTosh
1
@ MojoTosh du hast recht. Sie verwenden ListView und führen die Animation mit Code durch. expandAlarmFunktion in AlarmClockFragment.javaDateien führt den Erweiterungsteil aus.
user2731584
4
Welches onClick()soll ich überschreiben? Es gibt keine onClickim Adapter.
Vicky Leong
15

Es gibt eine sehr einfach zu verwendende Bibliothek mit Gradle-Unterstützung: https://github.com/cachapa/ExpandableLayout .

Direkt aus den Bibliotheksdokumenten:

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

Nachdem Sie Ihre erweiterbaren Ansichten markiert haben , rufen Sie einfach eine dieser Methoden für den Container auf : expand(), collapse()odertoggle()

Laurențiu Onac
quelle
Ist das immer noch der beste Weg, es zu tun? Ich versuche zu folgen, was du geschrieben hast. Ich habe einige Recycling-Ansichten, die ich erweitern möchte, um ein Diagramm
anzuzeigen,
10

Ich weiß, es ist lange her, dass die ursprüngliche Frage veröffentlicht wurde. Aber ich denke für langsame wie mich würde eine Erklärung der Antwort von @ Heisenberg helfen.

Deklarieren Sie zwei Variablen in der Adapterklasse als

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

Dann in onBindViewHolder wie in der ursprünglichen Antwort angegeben.

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

Und schließlich, um das recyclerView-Objekt in der Adapterüberschreibung zu erhalten

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

    this.recyclerView = recyclerView;
}

Hoffe das hilft.

shahroz hintern
quelle
3
Tolle und einfache Lösung. Kleine Verbesserung, verwenden Sie RecyclerView.NO_POSITION anstelle der magischen Zahl -1.
Casper Bang
8

Es ist einfach nicht erforderlich, Bibliotheken von Drittanbietern zu verwenden. Eine kleine Änderung an der in Google I / O 2016 demonstrierten Methode und Heisenberg zu diesem Thema vorgestellten reicht aus.

Da das notifyDataSetChanged() Ganze neu gezeichnet wirdRecyclerView , notifyDataItemChanged()ist dies eine bessere Option (nicht die beste), da wir die Position und das ViewHolderzur Verfügung haben und notifyDataItemChanged()nur das Besondere ViewHolderan einer bestimmten Position neu zeichnen .

Das Problem ist jedoch, dass das vorzeitige Verschwinden des ViewHolderbeim Klicken und dessen Auftreten nicht beseitigt wird, selbst wennnotifyDataItemChanged() es verwendet wird.

Der folgende Code greift nicht auf notifyDataSetChanged()oder zurück notifyDataItemChanged()und wird auf API 23 getestet und funktioniert wie ein Zauber, wenn er in einer RecyclerView verwendet wird, in der jeder ViewHolder ein Stammelement hat CardView:

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 ist eine globale Ganzzahl, die mit -1 initialisiert ist. detailsist die vollständige Ansicht, die beim Erweitern angezeigt und beim Reduzieren getarnt wird.

Wie gesagt, das Wurzelelement von ViewHolderist ein CardViewmit foregroundundstateListAnimator Attribute, die genau so definiert sind, wie es Heisenberg zu diesem Thema gesagt hat.

UPDATE: Die obige Demonstration wird das zuvor erweiterte Element reduzieren, wenn eines davon erweitert wird. Um dieses Verhalten zu ändern und das erweiterte Element so zu belassen, wie es ist, auch wenn ein anderes Element erweitert wird, benötigen Sie den folgenden Code.

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

UPDATE: Wenn Sie die letzten Elemente in der Liste erweitern, wird sie möglicherweise nicht vollständig sichtbar, da der erweiterte Bereich unter dem Bildschirm angezeigt wird. Verwenden Sie den folgenden Code, um das vollständige Element auf dem Bildschirm anzuzeigen.

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

WICHTIG: Damit die oben genannten Demonstrationen funktionieren, muss eine Instanz von RecyclerView und dessen LayoutManager (der spätere aus Gründen der Flexibilität) in ihrem Code gespeichert werden.

Koushik Shom Choudhury
quelle
Danke, diese Lösung funktioniert bei mir. Ich versuche zu vermeiden, notifyItemChangedweil ich ein ImageViewBild habe, das von einer URL geladen wird. notifyItemChangedNachladen meines Bildes sieht es komisch aus
Tam Huynh
Die Linie, die es nagelt, ist ein TransitionManager.beginDelayedTransition(recycler);großartiger Fund. Aber ich fand heraus, dass bei Verwendung dieser Methode, wenn ich mehrere Zeilen nacheinander auf Spam klicke, dies schließlich einen internen Absturz auslöst The specified child already has a parent. You must call removeView() on the child's parent first. Ich kann mir vorstellen, dass dies auf das Sichtrecycling innerhalb der Sichtgrenzen des Recyclers zurückzuführen ist, aber ich kann es nicht genau sagen. Hatte jemand das gleiche Problem?
Roger Oba
Ist das immer noch der beste Weg, es zu tun? Ich versuche zu folgen, was du geschrieben hast. Ich habe einige Recycling-Ansichten, die ich erweitern möchte, um beim Klicken ein Diagramm anzuzeigen. Es fällt mir schwer, genau zu verstehen, was zu tun ist
Sourlemonaid
Hat jemand das vollständige Beispiel dieser Implementierung? Ich meine ein funktionierendes Codebeispiel. Bitte helfen Sie. Ich kann nicht verstehen, wie es geht?
Munazza
7

Nach der Verwendung mit Wohnsitz der empfohlene Weg erweiterbare / reduzierbare Elemente der Umsetzung in ein RecyclerViewauf RecyclerView Aufklappen / Zuklappen Artikel beantwortet von Heisen , habe ich einige deutliche Artefakte zu sehen , wenn der RecyclerViewdurch den Aufruf aktualisiert wird TransitionManager.beginDelayedTransition(ViewGroup)und anschließend notifyDatasetChanged().

Seine ursprüngliche Antwort:

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

Geändert:

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());
    }
}
  • Details ist eine Ansicht, die Sie beim Erweitern / Reduzieren von Elementen ein- / ausblenden möchten
  • mExpandedPosition ist eine int, die das erweiterte Element verfolgt
  • mExpandedHolder wird ViewHolderbeim Reduzieren von Elementen verwendet

Beachten Sie, dass die Methode TransitionManager.beginDelayedTransition(ViewGroup)und notifyDataSetChanged()ersetzt werden, um notifyItemChanged(int)auf ein bestimmtes Element und einige kleine Verbesserungen abzuzielen.

Nach der Änderung sollten die vorherigen unerwünschten Effekte verschwunden sein. Dies ist jedoch möglicherweise nicht die perfekte Lösung. Es hat nur getan, was ich wollte, und die Schandflecken beseitigt.

::BEARBEITEN::

Zur Verdeutlichung sind beide mExpandedPositionund mExpandedHolderglobal.

Chan Teck Wei
quelle
Bitte erläutern Sie, wie und wo mExpandedHolder deklariert und verwendet wird.
Werner
1
@Werner Ich habe die Antwort bearbeitet, um zu zeigen, wo sie deklariert ist. Die Verwendung liegt sowohl innerhalb des Snippets selbst als auch innerhalb des Zwecks. Es wird verwendet, um kollabierende, erweiterte Elemente zu animieren.
Chan Teck Wei
Ich liebe diesen Ansatz am meisten, was die Animationen betrifft, aber ich habe diese kleine "Überblendung", wenn ich auf das Element klicke. Haben Sie das auch oder anders ausgedrückt, liegt dies an der Verwendung von notifyItemChanged ()? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/…
Kazume
Ja. Wie Sie vermutet haben, wird es verursacht durch notifyItemChanged(). Sie können die Elementhöhe manuell animieren, ändern und Ansichten hinzufügen.
Chan Teck Wei
@ChanTeckWei: Ihre Lösung funktioniert einwandfrei, aber das Zeilenbild flackert, wenn ich die Zeile mit dem Recycling-Ansichtselement reduziere oder erweitere. Gibt es eine Lösung dafür?
Pragya Mendiratta
3

Gehen Sie wie folgt vor, nachdem Sie den onClick-Listener auf die ViewHolder-Klasse festgelegt haben:

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

Ich denke, das sollte helfen, so habe ich es implementiert und mache das gleiche, was Google in der letzten Anrufansicht macht.

Rensodarwin
quelle
2

Ich bin überrascht, dass es noch keine präzise Antwort gibt, obwohl eine solche Animation zum Erweitern / Reduzieren mit nur 2 Codezeilen sehr einfach zu erreichen ist:

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

zusammen mit

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

Für mich waren die Erklärungen im folgenden Link wirklich nützlich: https://medium.com/@nikola.jakshic/how-to-expand-collapse-items-in-recyclerview-49a648a403a6

Bianca Daniciuc
quelle
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);
        }
}

Geben Sie hier die Bildbeschreibung ein

Keshav Gera
quelle
0

Verwenden Sie zwei Ansichtstypen in Ihrem RVAdapter. Eine für erweitertes Layout und eine für reduziert. Und die Magie entsteht, wenn Sie android:animateLayoutChanges="true"für RecyclerView Checkout den Effekt festlegen, der in diesem Video um 0:42 Uhr erzielt wird

penduDev
quelle
Darf ich das besser erklären? Ich kann es nicht zum
Laufen
@sourlemonaid Grundsätzlich erstellen Sie mehrere Ansichtstypen für die Liste, wie unter stackoverflow.com/a/26245463/3731795 erläutert. Sie verfolgen den Index, für den das Element erweitert wird, und der Rest der Elemente wird zu diesem Zeitpunkt reduziert . Nun, wenn (current_item_index == expandierter_item_index) {return VIEW_TYPE_EXPANDED} else {reutrn VIEW_TYPE_COLLAPSED}
penduDev