Ist es möglich, erweiterbare Listenelemente mit dem neuen RecyclerView zu verwenden? Wie ExpandableListView?
Ist es möglich, erweiterbare Listenelemente mit dem neuen RecyclerView zu verwenden? Wie ExpandableListView?
Antworten:
Dies ist mit den Standard-LayoutManagern einfach zu tun. Alles hängt davon ab, wie Sie Ihren Adapter verwalten.
Wenn Sie einen Abschnitt erweitern möchten, fügen Sie Ihrem Adapter nach der Kopfzeile einfach neue Elemente hinzu. Denken Sie daran, notifyItemRangeInserted aufzurufen, wenn Sie dies tun. Um einen Abschnitt zu reduzieren, entfernen Sie einfach die relevanten Elemente und rufen notifyItemRangeRemoved () auf. Bei Datenänderungen, die entsprechend benachrichtigt werden, werden die Ansichten in der Recycler-Ansicht animiert. Beim Hinzufügen von Elementen wird ein Bereich erstellt, der mit den neuen Elementen gefüllt werden soll, wobei die neuen Elemente eingeblendet werden. Das Entfernen ist das Gegenteil. Neben dem Adapter müssen Sie lediglich Ihre Ansichten formatieren, um dem Benutzer die logische Struktur zu vermitteln.
Update: Ryan Brooks hat jetzt einen Artikel darüber geschrieben .
Holen Sie sich das Beispielcode Implementierung von hier
Legen Sie ValueAnimator in onClick von ViewHolder fest
@Override
public void onClick(final View view) {
if (mOriginalHeight == 0) {
mOriginalHeight = view.getHeight();
}
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
}
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
Hier ist der endgültige Code
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mFriendName;
private int mOriginalHeight = 0;
private boolean mIsViewExpanded = false;
public ViewHolder(RelativeLayout v) {
super(v);
mFriendName = (TextView) v.findViewById(R.id.friendName);
v.setOnClickListener(this);
}
@Override
public void onClick(final View view) {
if (mOriginalHeight == 0) {
mOriginalHeight = view.getHeight();
}
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight, mOriginalHeight + (int) (mOriginalHeight * 1.5));
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(mOriginalHeight + (int) (mOriginalHeight * 1.5), mOriginalHeight);
}
valueAnimator.setDuration(300);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
}
ExpandableListView
", da der erweiterte Inhalt in diesem Fall eine Liste mit Elementen ist, die vom Adapter stammen. Dies ist eine entartete Lösung, bei der nur 1 Element als Kinder innerhalb der Gruppe zulässig ist.
https://github.com/gabrielemariotti/cardslib
Diese Bibliothek verfügt über eine Implementierung einer erweiterbaren Liste mit einer Recycling-Ansicht (siehe die Demo-App unter "CardViewNative" -> "Liste, Raster und RecyclerView" -> "Erweiterbare Karten"). Es hat auch viele andere coole Kombinationen von Karten / Listen.
Jemand hat sich darüber beschwert, dass die oben genannte Lösung mit einer Listenansicht nicht als erweiterbarer Inhalt verwendet werden kann. Es gibt jedoch eine einfache Lösung: Erstellen Sie eine Listenansicht und füllen Sie diese Listenansicht manuell mit Ihren Zeilen .
Lösung für die Faulen: Es gibt eine einfache Lösung, wenn Sie Ihren Code nicht zu stark ändern möchten. Verwenden Sie einfach Ihren Adapter manuell, um Ansichten zu erstellen und sie dem hinzuzufügen LinearLayout
.
Hier ist das Beispiel:
if (mIsExpanded)
{
// llExpandable... is the expandable nested LinearLayout
llExpandable.removeAllViews();
final ArrayAdapter<?> adapter = ... // create your adapter as if you would use it for a ListView
for (int i = 0; i < adapter.getCount(); i++)
{
View item = adapter.getView(i, null, null);
// if you want the item to be selectable as if it would be in a default ListView, then you can add following code as well:
item.setBackgroundResource(Functions.getThemeReference(context, android.R.attr.selectableItemBackground));
item.setTag(i);
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// item would be retrieved with:
// adapter.getItem((Integer)v.getTag())
}
});
llExpandable.addView(item);
}
ExpandUtils.expand(llExpandable, null, 500);
}
else
{
ExpandUtils.collapse(llExpandable, null, 500);
}
Hilfsfunktionen: getThemeReference
public static int getThemeReference(Context context, int attribute)
{
TypedValue typeValue = new TypedValue();
context.getTheme().resolveAttribute(attribute, typeValue, false);
if (typeValue.type == TypedValue.TYPE_REFERENCE)
{
int ref = typeValue.data;
return ref;
}
else
{
return -1;
}
}
Hilfsklasse: ExpandUtils
Kavin Varnan postet bereits, wie man ein Layout animiert ... Aber wenn Sie meine Klasse verwenden möchten, können Sie dies gerne tun: https://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a
recyclerview
und Sie können diese verschachtelte Ansicht erweitern / ausblenden und alle Optimierungen desrecyclerview
Sie können ExpandableLayout verwenden, das einer reibungslosen CheckBox zum Erweitern / Reduzieren von Animationen ähnelt, sodass Sie es als CheckBox in ListView und RecyclerView verwenden können.
Dies ist der Beispielcode für das, was von @TonicArtos erwähnt wird, um Elemente hinzuzufügen und zu entfernen und es dabei zu animieren. Dies stammt aus dem RecyclerView Animations- und GitHub-Beispiel
1) Fügen Sie Listener in Ihren onCreateViewHolder () ein, um sich für onClick zu registrieren
2) Erstellen Sie Ihren benutzerdefinierten OnClickListener in Ihrem Adapter
private View.OnClickListener mItemListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView tv = (TextView) v.findViewById(R.id.tvItems);
String selected = tv.getText().toString();
boolean checked = itemsList.get(recyclerView.getChildAdapterPosition(v)).isChecked();
switch (selected){
case "Item1":
if(checked){
deleteItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
}else {
addItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
}
break;
case "Item2":
if(checked){
deleteItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(false);
}else {
addItem(v);
itemsList.get(recyclerView.getChildAdapterPosition(v)).setChecked(true);
}
break;
default:
//In my case I have checkList in subItems,
//checkItem(v);
break;
}
}
};
3) Fügen Sie Ihr addItem () und deleteItem () hinzu
private void addItem(View view){
int position = recyclerView.getChildLayoutPosition(view);
if (position != RecyclerView.NO_POSITION){
navDrawItems.add(position+1,new mObject());
navDrawItems.add(position+2,new mObject());
notifyItemRangeInserted(position+1,2);
}
}
private void deleteItem(View view) {
int position = recyclerView.getChildLayoutPosition(view);
if (position != RecyclerView.NO_POSITION) {
navDrawItems.remove(position+2);
navDrawItems.remove(position+1);
notifyItemRangeRemoved(position+1,2);
}
}
4) Wenn sich Ihr RecyclerViewAdapter nicht in derselben Aktivität wie die Recycler-Ansicht befindet , übergeben Sie beim Erstellen die Instanz von recyclerView an den Adapter
5) itemList ist eine ArrayList vom Typ mObject, mit deren Hilfe der Status von Element (Öffnen / Schließen), Name, Elementtyp (subItems / mainItem) und das Thema basierend auf Werten festgelegt werden können
public class mObject{
private String label;
private int type;
private boolean checked;
}