Czy w nowym RecyclerView można używać rozwijanych elementów listy? Podoba Ci się ExpandableListView?
Czy w nowym RecyclerView można używać rozwijanych elementów listy? Podoba Ci się ExpandableListView?
Odpowiedzi:
Jest to łatwe do zrobienia za pomocą standardowych LayoutManagerów, wszystko zależy od tego, jak zarządzasz kartą.
Jeśli chcesz rozwinąć sekcję, po prostu dodaj nowe elementy do adaptera po nagłówku. Pamiętaj, aby w tym celu zadzwonić do notificationItemRangeInserted. Aby zwinąć sekcję, po prostu usuwasz odpowiednie elementy i wywołujesz notifyItemRangeRemoved (). W przypadku wszelkich zmian danych, które zostaną odpowiednio zgłoszone, widok recyklera będzie animował widoki. Podczas dodawania elementów tworzony jest obszar, który ma zostać wypełniony nowymi elementami, a nowe elementy znikają. Usuwanie jest odwrotne. Jedyne, co musisz zrobić, poza elementami adaptera, to stylizować widoki, aby przekazać logiczną strukturę użytkownikowi.
Aktualizacja: Ryan Brooks napisał teraz artykuł o tym, jak to zrobić.
Pobierz przykładową implementację kodu stąd
Ustaw ValueAnimator wewnątrz onClick of ViewHolder
@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();
}
Oto ostateczny kod
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
”, ponieważ w tym przypadku rozwinięta zawartość jest listą zawierającą elementy pochodzące z adaptera. To zdegenerowane rozwiązanie, w którym tylko 1 pozycja jest dozwolona jako dzieci w grupie.
https://github.com/gabrielemariotti/cardslib
Ta biblioteka zawiera implementację listy rozwijanej z widokiem recyklingu (patrz aplikacja demonstracyjna w sekcji „CardViewNative” -> „List, Grid i RecyclerView” -> „Expandable cards”). Zawiera również wiele innych fajnych kombinacji kart / list.
Ktoś narzekał, że powyższe rozwiązanie nie nadaje się do użytku z widokiem listy jako treścią rozwijaną. Ale jest proste rozwiązanie: utwórz widok listy i wypełnij ten widok listy ręcznie swoimi wierszami .
Rozwiązanie dla leniwych: istnieje proste rozwiązanie, jeśli nie chcesz zbytnio zmieniać kodu. Po prostu ręcznie użyj adaptera, aby utworzyć widoki i dodać je do LinearLayout
.
Oto przykład:
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);
}
funkcje pomocnicze: 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;
}
}
klasa pomocnika: ExpandUtils
Kavin Varnan postet już, jak animować układ ... Ale jeśli chcesz skorzystać z mojej klasy, nie krępuj się, zamieściłem streszczenie: https://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a
recyclerview
i możesz rozwinąć / ukryć ten zagnieżdżony widok i wykorzystać wszystkie optymalizacjerecyclerview
Możesz użyć ExpandableLayout, który przypomina płynną animację rozwijania / zwijania CheckBox, dzięki czemu możesz go używać jako CheckBox w ListView i RecyclerView.
To jest przykładowy kod tego, o czym wspomina @TonicArtos, aby dodawać i usuwać elementy oraz animować go podczas wykonywania, pochodzi z RecyclerView Animations i przykład GitHub
1) Dodaj Listener wewnątrz swojej onCreateViewHolder (), aby zarejestrować się w onClick
2) Utwórz niestandardowy OnClickListener wewnątrz adaptera
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) Dodaj swój addItem () i deleteItem ()
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) Jeśli RecyclerViewAdapter nie jest w tym samym działalność jako Recycler View , przechodzą instancję recyclerView do zasilacza podczas tworzenia
5) itemList to ArrayList typu mObject, który pomaga zachować stany pozycji (Open / Close), nazwę, typ Item (subItems / mainItem) i ustawić motyw na podstawie wartości
public class mObject{
private String label;
private int type;
private boolean checked;
}