RecyclerView развернуть / свернуть элементы

145

Я хочу развернуть / свернуть элементы моего recyclerView, чтобы показать больше информации. Я хочу добиться того же эффекта от SlideExpandableListView .

В основном в моем viewHolder у меня есть вид, который не виден, и я хочу сделать плавную анимацию развертывания / сворачивания, а не устанавливать видимость только VISIBLE / GONE. Мне нужно только расширить элемент за раз, и было бы здорово иметь некоторую отметку, чтобы показать, что элемент выбран.

Это тот же эффект, что и в новом списке недавних звонков Android. Параметры «ОБРАТНАЯ СВЯЗЬ» и «ДЕТАЛИ» отображаются только при выборе элемента.

RecyclerView расширяемые элементы

stanete
источник
У меня есть связанный вопрос. В приложении «Часы» активность по установке будильника имеет аналогичную функцию. Это сделано так же?
user2731584
Эй, у тебя есть решение? Я также ищу то же решение для моего приложения.
Арпит Патель
Вы нашли какое-нибудь решение?
Армин Гореиши
1
Я обновил рекомендуемый способ сделать это в соответствии с Google I / O 2016. См. Мой ответ stackoverflow.com/questions/27203817/…
Гейзенберг
проверьте мой ответ здесь простое и классное решение stackoverflow.com/a/48092441/5962715
Киран Бенни Джозеф

Ответы:

192

Пожалуйста, не используйте какую-либо библиотеку для этого эффекта, вместо этого используйте рекомендуемый способ сделать это в соответствии с Google I / O. В методе onBindViewHolder вашего recyclerView сделайте это:

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();
    }
});
  • Где детали это мой вид, который будет отображаться на ощупь (детали звонка в вашем случае. По умолчанию Visibility.GONE).
  • mExpandedPosition - это переменная типа int, инициализированная -1

А для классных эффектов, которые вы хотели, используйте их в качестве атрибутов list_item:

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

где 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>

и 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
При использовании этого кода расширение-анимация выглядит странно. Каждый раз, когда верхний элемент исчезает, и все сдвигается на одну позицию. Вы когда-нибудь испытывали нечто подобное?
chris-pollx
6
Я пытаюсь сделать анимацию, но я реализую это на адаптере, но каково было бы решение, TransitionManager.beginDelayedTransition(recyclerView);если я не могу получить ссылку на представление переработчика.
Мартин Серрано
2
@Ranveer Это работает вроде. У меня есть два довольно похожих вьюблера, но он корректно работает только для одного. Понятия не имею почему. @ MartínDaniel Вы должны передать в recyclerViewкачестве параметра в конструкторе для адаптера
chris-
26
Это ужасный подход. Я не могу поверить, что это было рекомендовано в Google I / O. Даже после изучения проекта Plaid и реализации всех необходимых обходных путей, анимация все еще вызывает некоторые серьезные сбои в RecyclerView, например, первый / последний видимый элемент исчезает преждевременно. Кроме того, прокрутка во время анимации все портит. В целом, я не думаю, что решение всех проблем, вызванных этим подходом, можно назвать «просто поставьте одну строку, и все будет работать», как рекламируется.
Виталий Ольшевский
6
Есть ли у нас более свежий и легкий способ решения этой проблемы в 2019 году?
Пономаренко Олег
76

Для этого просто нужны простые линии, не сложные

в вашем методе onBindViewHolder добавьте ниже код

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 - это глобальная переменная int, инициализированная -1

Для тех, кто хочет, чтобы только один предмет был расширен, а другие развалились. Использовать это

сначала объявите глобальную переменную с previousExpandedPosition = -1

затем

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

Готово!!!. Просто и скромно .. :)

Киран Бенни Джозеф
источник
отличное решение. Также я бы рекомендовал перенести настройки OnClickListeners onCreateViewHolderвместоonBindViewHolder
YTerle
1
Работает очень хорошо, со временем было приличное решение, которое просто позволяет RecyclerViewделать работу, я имею в виду, какой смысл LayoutManagerиначе, если он не управляет макетами! Это решение лучше, чем решение с наибольшим количеством голосов, так как оно содержит меньше кода, позволяет RecyclerViewсправляться с проблемами и работает лучше!
Марк Кин
1
не совсем понял, как добавить "детали" вид. Должно ли оно быть статичным для каждого держателя? Что если для каждого элемента списка мне нужно добавить разные представления?
BekaBot
@BekaBot это вид, который вы хотите скрыть во время свертывания предмета
Киран Бенни Джозеф
@KiranBennyJoseph да, я понимаю. В этом случае вид должен быть одинаковым для всех предметов? Что делать, если я хочу разные виды для разных предметов?
BekaBot
72

Не сказать, что это лучший подход, но, похоже, он мне подходит.

Полный код можно найти по адресу: Пример кода по адресу: https://github.com/dbleicher/recyclerview-grid-quickreturn

Прежде всего, добавьте расширенную область в макет ячейки / элемента и сделайте компоновку вмещающей ячейки animateLayoutChanges = "true". Это обеспечит анимацию развертывания / свертывания:

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

Затем сделайте так, чтобы ваш класс адаптера RV реализовал View.OnClickListener, чтобы вы могли воздействовать на элемент, по которому щелкали. Добавьте поле int для хранения позиции одного расширенного представления и инициализируйте его отрицательным значением:

private int expandedPosition = -1;

Наконец, реализуйте методы ViewHolder, onBindViewHolder () и переопределите метод onClick (). Вы развернете представление в onBindViewHolder, если его позиция равна «extendedPosition», и скроете его, если нет. Вы устанавливаете значение extendedPosition в слушателе 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);
    }
}

Это должно расширять только один элемент за один раз, используя системную анимацию по умолчанию для изменения макета. По крайней мере, это работает для меня. Надеюсь, поможет.

MojoTosh
источник
Я знаю, как сохранить только один элемент. Я действительно не знаю, как сделать анимацию на этом предмете. Анимация развертывания / свертывания с системной анимацией по умолчанию выглядит не очень гладко.
Станете
1
Я еще не пробовал следующее, но это, похоже, будет работать. Проверьте ответ по адресу: stackoverflow.com/a/26443762/2259418
MojoTosh
2
@ user2731584 - Я так не думаю. Глядя на (как мне кажется, это) их источник, кажется, что часы Lollipop используют ListView для отображения списка сигналов тревоги. Макет: android.googlesource.com/platform/packages/apps/DeskClock/+/… Похоже, они имеют собственный код для анимации элементов раскрытия / свертывания в этом списке. См. Следующий источник: android.googlesource.com/platform/packages/apps/DeskClock/+/…
MojoTosh
1
@MojoTosh ты прав. Они используют ListView и делают анимацию, используя код. expandAlarmФункция в AlarmClockFragment.javaфайлах выполняет часть расширения.
user2731584
4
Что onClick()я должен переопределить? Там нет onClickв адаптере.
Вики Леонг
15

Существует очень простая в использовании библиотека с поддержкой gradle: https://github.com/cachapa/ExpandableLayout .

Прямо из библиотеки документов:

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

После того, как вы отмечаете свое расширяющиеся точки зрения, просто вызвать любого из этих методов на контейнере: expand(), collapse()илиtoggle()

Laurențiu Onac
источник
Это все еще лучший способ сделать это? Я пытаюсь следовать тому, что вы написали. У меня есть некоторые виды рециркуляции, которые я хочу развернуть, чтобы показать график при нажатии
sourlemonaid
10

Я знаю, что прошло много времени с тех пор, как был опубликован оригинальный вопрос. Но я думаю, что для таких, как я, небольшое объяснение ответа @ Heisenberg поможет.

Объявите две переменные в классе адаптера как

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

Затем в onBindViewHolder, следуя указаниям оригинального ответа.

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

И, наконец, чтобы получить объект recyclerView в переопределении адаптера

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

    this.recyclerView = recyclerView;
}

Надеюсь это поможет.

приклад шахроса
источник
3
Отличное и простое решение. Небольшое улучшение, используйте RecyclerView.NO_POSITION вместо магического числа -1.
Каспер Банг
8

Нет необходимости использовать сторонние библиотеки. Небольшая настройка метода, продемонстрированного в Google I / O 2016 и Гейзенберге на эту тему, делает свое дело.

Поскольку notifyDataSetChanged() перерисовывает полныйRecyclerView , notifyDataItemChanged()это лучший вариант (не лучший), потому что у нас есть позиция и ViewHolderв нашем распоряжении, и notifyDataItemChanged()только перерисовывает конкретный ViewHolderв данной позиции .

Но проблема в том, что преждевременное исчезновение ViewHolderщелчка и его появление не устраняется, даже если notifyDataItemChanged()используется.

Следующий код не прибегать к notifyDataSetChanged()или notifyDataItemChanged()и испытано на API 23 и работает как шарм при использовании на RecyclerView , где каждый ViewHolder имеет , 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глобальное целое число, инициализированное -1. detailsэто полное представление, которое отображается в развернутом виде и скрыто при свертывании.

Как уже говорилось, корневой элемент ViewHolder- это атрибуты CardViewwith foregroundи stateListAnimatorопределены точно так, как сказал Гейзенберг по этой теме.

ОБНОВЛЕНИЕ: Приведенная выше демонстрация свернет ранее развернутый элемент, если один из них развернут. Чтобы изменить это поведение и сохранить развернутый элемент таким, какой он есть, даже когда другой элемент развернут, вам потребуется следующий код.

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

ОБНОВЛЕНИЕ: при развертывании последних элементов в списке, он может не отображаться в полной видимости, потому что расширенная часть находится ниже экрана. Чтобы получить полный элемент на экране, используйте следующий код.

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

ВАЖНО: чтобы вышеприведенные демонстрации работали, в их коде необходимо сохранить экземпляр RecyclerView и его LayoutManager (последний для гибкости)

Кушик Шом Чоудхури
источник
Спасибо, это решение работает для меня. Я стараюсь избегать использования, notifyItemChangedпотому что у меня есть ImageViewизображение загрузки с URL. notifyItemChangedперезагрузить мое изображение делает это выглядит странно
Там Хейн
Линия, которая прибивает это TransitionManager.beginDelayedTransition(recycler);, большая находка. Но я обнаружил, что при использовании этого метода, если я последовательно щелкаю спам по нескольким строкам, это в конечном итоге вызывает внутренний сбой The specified child already has a parent. You must call removeView() on the child's parent first. Я предполагаю, что это происходит из-за представления рециркуляции на границах представления рециркулятора, но я не могу сказать точно. У кого-нибудь была такая же проблема?
Роджер Оба
Это все еще лучший способ сделать это? Я пытаюсь следовать тому, что вы написали. У меня есть некоторые повторные представления, которые я хочу развернуть, чтобы показать график при нажатии. Мне трудно понять, что именно делать
Sourlemonaid
У кого-нибудь есть полный пример этой реализации? Я имею в виду пример рабочего кода. Пожалуйста помоги. Я не могу понять, как это сделать?
Мунацца
7

После использования рекомендованного способа реализации расширяемых / складываемых элементов, находящихся в элементах раскрытия / сворачивания RecyclerView,RecyclerView на которые ответил HeisenBerg , я видел некоторые заметные артефакты всякий раз, когда они RecyclerViewобновляются путем вызова TransitionManager.beginDelayedTransition(ViewGroup)и впоследствии notifyDatasetChanged().

Его оригинальный ответ:

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

Изменен:

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());
    }
}
  • подробная информация - это вид, который вы хотите показать / скрыть во время раскрытия / сворачивания элемента
  • mExpandedPosition - это intотслеживание расширенного элемента.
  • mExpandedHolder является ViewHolderиспользуется во время распада элемента

Обратите внимание, что метод TransitionManager.beginDelayedTransition(ViewGroup)и notifyDataSetChanged()заменены notifyItemChanged(int)на целевой элемент и некоторые небольшие изменения.

После модификации предыдущие нежелательные эффекты должны исчезнуть. Тем не менее, это не может быть идеальным решением. Он делал только то, что хотел, устраняя глазные раны.

::РЕДАКТИРОВАТЬ::

Для пояснения, оба mExpandedPositionи mExpandedHolderявляются глобальными.

Чан Тек Вей
источник
Пожалуйста, объясните, как и где mExpandedHolder объявлен и используется?
Вернер
1
@ Вернер Я отредактировал ответ, чтобы показать, где он объявлен. Использование находится внутри самого фрагмента, а также цели. Используется для анимации разворачивающегося, развернутого предмета.
Чан Тек Вэй
Мне нравится этот подход больше всего в том, что касается анимации, но при щелчке по этому элементу у меня возникает небольшое «затухание». Есть ли у вас это, или по-другому, это связано с использованием notifyItemChanged ()? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/…
kazume
Да. Как вы уже догадались, это вызвано notifyItemChanged(). Вы можете вручную анимировать и изменять высоту элемента и добавлять виды в него.
Чан Тек Вей
@ChanTeckWei: ваше решение работает нормально, но изображение строки мерцает всякий раз, когда я сворачиваю или раскрываю строку элемента в окне реселлера. Есть ли для этого решение?
Прагья Мендиратта
3

Выполните следующие действия после установки прослушивателя onClick для класса 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();
    }
}

Я думаю, что это должно помочь, вот как я реализовал и делает то же самое, что делает Google в представлении недавних вызовов.

Rensodarwin
источник
3

Я удивлен, что пока нет четкого ответа, хотя такую ​​анимацию разворачивания / свертывания очень легко достичь всего с двумя строками кода:

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

вместе с

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

Так что для меня объяснения в ссылке ниже были действительно полезны: 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);
        }
}

введите описание изображения здесь

Кешав Гера
источник
0

Используйте два типа просмотра в вашем RVAdapter. Один для расширенного макета, а другой для свернутого. И волшебство происходит с настройкой android:animateLayoutChanges="true"для RecyclerView Checkout эффекта, достигнутого с помощью этого в 0:42 в этом видео

penduDev
источник
возражаете объяснить это лучше? Я не могу заставить его работать
sourlemonaid
@sourlemonaid, в основном, вы создаете несколько типов представлений для списка, как описано в stackoverflow.com/a/26245463/3731795 ... Вы отслеживаете индекс, для которого элемент развернут, а остальные элементы свернуты в это время. , Теперь if (current_item_index == extended_item_index) {вернуть VIEW_TYPE_EXPANDED} else {reutrn VIEW_TYPE_COLLAPSED}
penduDev