Расширяемый список с RecyclerView?

Можно использовать расширяемые элементы списка с новым RecyclerView? Как ExpandableListView?

Ответ 1

Это просто сделать с менеджерами LayoutManager, все зависит от того, как вы управляете своим адаптером.

Если вы хотите развернуть раздел, вы просто добавляете новые элементы в свой адаптер после заголовка. Не забудьте вызвать notifyItemRangeInserted, когда вы это сделаете. Чтобы свернуть раздел, вы просто удаляете соответствующие элементы и вызываете notifyItemRangeRemoved(). Для любых изменений данных, которые будут соответствующим образом уведомлены, просмотр recycler будет анимировать представления. При добавлении элементов создается область, заполняемая новыми элементами, при этом исчезают новые элементы. Удаление - это противоположное. Все, что вам нужно сделать, помимо материала адаптера, - это стиль ваших представлений, чтобы передать логическую структуру пользователю.

Обновление: Райан Брукс написал статью о том, как это сделать.

Ответ 2

Получить пример реализации кода из здесь

Установить ValueAnimator внутри 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();

}

Вот окончательный код

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

    }
}

Ответ 3

https://github.com/gabrielemariotti/cardslib

В этой библиотеке есть реализация расширяемого списка с recyclerview (см. демонстрационное приложение под "CardViewNative" → "Список, сетка и RecyclerView" → "Расширяемые карты" ). В нем также есть много других интересных комбинаций карт/списков.

Ответ 4

Кто-то жаловался, что вышеупомянутое решение не может использоваться в качестве расширяемого контента. Но есть простое решение: создать список и заполнить этот список вручную своими строками.

Решение для ленивых: есть простое решение, если вы не хотите сильно менять свой код. Просто используйте адаптер для создания представлений и добавьте их в LinearLayout.

Вот пример:

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

вспомогательные функции: 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;
    }
}

вспомогательный класс: ExpandUtils

Кавин Варнан опубликовал уже как анимировать макет... Но если вы хотите использовать мой класс, не стесняйтесь делать это, я разместил суть: https://gist.github.com/MichaelFlisar/738dfa03a1579cc7338a

Ответ 5

Вы можете использовать ExpandableLayout, как плавное расширение/сбой анимации CheckBox, поэтому вы можете использовать его как CheckBox в ListView и RecyclerView.

https://github.com/KyoSherlock/ExpandableLayout

Ответ 6

Это пример кода для того, что указано @TonicArtos, чтобы добавлять и удалять элементы и анимировать их во время выполнения, это берется из Анимации RecyclerView и Пример GitHub

1) Добавить прослушиватель внутри onCreateViewHolder() для регистрации onClick

2) Создайте свой собственный OnClickListener внутри вашего адаптера

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) Добавьте свой addItem() и 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) Если ваш RecyclerViewAdapter не находится в том же действии, что и просмотр ресайклеров, передайте экземпляр recyclerView в Adapter при создании p >

5) itemList - это массив ArrayList типа mObject, который помогает поддерживать состояние элемента (Open/Close), имя, тип элемента (subItems/mainItem) и задавать Тема, основанная на значениях

public class mObject{
    private String label;
    private int type;
    private boolean checked;
}