RecyclerView елементи розширення / згортання


145

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

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

Це такий же ефект від нового списку історії останніх дзвінків Android. Параметри "CALL BACK" та "DETALS" відображаються лише при виборі елемента.

RecyclerView елементи, що розширюються


У мене пов'язане питання. У додатку Clock активність набору тривожних сигналів має аналогічну особливість. Це робиться так само?
користувач2731584

Гей, у вас є рішення? Я також шукаю те саме рішення для свого додатка.
Арпіт Патель

Ви знайшли якесь рішення?
Армін Горейші

1
Я оновив рекомендований спосіб зробити це згідно Google I / O 2016. Дивіться мою відповідь stackoverflow.com/questions/27203817/…
Heisenberg

перевірте мою відповідь тут на просте і круте рішення stackoverflow.com/a/48092441/5962715
Кіран Бенні Джозеф

Відповіді:


192

Будь ласка, не використовуйте жодної бібліотеки для цього ефекту, а використовуйте рекомендований спосіб роботи відповідно до вводу / виводу Google. У методі onBindViewHolder вашого recilerView зробіть це:

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();
    }
});
  • Де детальніше - це мій погляд, який буде відображатися на дотик (дані про дзвінки у вашому випадку. Видимість за замовчуванням.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>

і коментар_вибір:

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

6
Я намагаюсь зробити анімацію, але я реалізую це на адаптері, але що було б рішенням, TransitionManager.beginDelayedTransition(recyclerView);якщо я не можу скористатися посиланням на перегляд рециркулятора.
Martín Serrano

2
@Ranveer Це працює на зразок. У мене є два досить схожих recilerView, але він працює тільки правильно для одного. Не знаю, чому. @ MartínDaniel Вам потрібно передати recyclerViewяк параметр у конструкторі адаптера
chris-pollux

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

Для тих, хто хоче розширити лише один предмет, а інші згорнутися. Використовуй це

спочатку оголосимо глобальну змінну з попереднімExpandedPosition = -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 = "вірно". Це забезпечить анімацію розгортання / згортання:

<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 Adapter реалізує View.OnClickListener, щоб ви могли діяти на елемент, який натискається. Додайте поле int, щоб утримувати позицію одного розширеного представлення, і ініціалізуйте його до негативного значення:

private int expandedPosition = -1;

Нарешті, реалізуйте свої методи ViewHolder, onBindViewHolder () та замініть метод onClick (). Ви розгорнете подання в onBindViewHolder, якщо його позиція дорівнює "розширеному положенню", і приховатимете його, якщо ні. Ви встановлюєте значення розширеноїПозиції у слухачі 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);
    }
}

Це має розширювати лише один елемент за один раз, використовуючи анімацію за замовчуванням системи для зміни макета. Принаймні, це працює для мене. Сподіваюся, це допомагає.


Я знаю, як вибрати лише один предмет. Я не знаю, як робити анімацію на цьому елементі. Анімація розгортання / згортання з анімацією за замовчуванням не виглядає дуже гладко.
stanete

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файлах виконує частину розширення.
користувач2731584

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


Це все-таки найкращий спосіб зробити це? Я намагаюся слідкувати за тим, що ви написали. У мене є кілька переглядів, які я хочу розгорнути, щоб відобразити графік при натисканні на
серлемонаїд

10

Я знаю, що минуло давно, як було розміщено оригінальне запитання. Але я думаю, що для повільних, як я, трохи пояснення відповіді @ Гейзенберга допоможе.

Оголосіть дві змінні в класі адаптера як

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

І останнє, щоб отримати об'єкт recilerView в перехідному адаптері

@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є CardViewз 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. Я думаю, це пов'язано з переробкою подання на межі перегляду утилізатора, але я не можу точно сказати. Хтось мав те саме питання?
Роджер Оба

Це все-таки найкращий спосіб зробити це? Я намагаюся слідкувати за тим, що ви написали. У мене є кілька переглядів, які я хочу розгорнути, щоб показати графік при натисканні на нього. Мені важко зрозуміти, що саме потрібно робити
сурлемонаїд

Хтось має повний приклад цієї реалізації? Я маю на увазі приклад робочого коду. Будь ласка, допоможіть. Я не в змозі зрозуміти, як це зробити?
Мунацца

7

Після використання рекомендований спосіб реалізації розширюваних / розбірних елементів , які проживають в RecyclerViewна RecyclerView розширення / пунктів колапси відповів на Гейзенберга , я бачив деякі помітні артефакти щоразу , коли 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)на націлення на конкретний предмет та деякі невеликі налаштування.

Після модифікації попередні небажані ефекти повинні бути зникли. Однак це може бути не ідеальним рішенням. Це робилося лише те, що я хотів, усуваючи окуляри.

:: EDIT ::

Для уточнення обидва є mExpandedPositionі mExpandedHolderглобальними.


Поясніть, будь ласка, як і де mExpandedHolder оголошується та використовується?
Вернер

1
@Werner Я відредагував відповідь, щоб показати, де вона оголошена. Використання є в межах самого фрагмента, а також у меті. Він використовується для анімації збірного, розгорнутого елемента.
Чан Тек Вей

Мені найбільше подобається такий підхід, що стосується анімації, але у мене це маленьке «згасання» при натисканні на предмет. Чи є у вас це чи по-іншому, це пов’язано з використанням notifyItemChanged ()? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/…
kazume

Так. Як ви здогадалися, це спричинено notifyItemChanged(). Ви можете вручну анімувати та змінювати висоту предмета та додавати до нього перегляди.
Чан Тек Вей

@ChanTeckWei: ваше рішення працює нормально, але зображення рядків мерехтять, коли я згортаю або розширюю рядок елемента рециркулятора. Чи є для цього рішення?
Pragya Mendiratta

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 виконує в недавньому перегляді дзвінків.


2

Я здивований, що ще немає стислої відповіді, хоча таку анімацію розширення / згортання досягти дуже просто за допомогою двох рядків коду:

(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 в цьому відео


розум пояснити це краще? Я не можу змусити його працювати
sourlemonaid

@sourlemonaid в основному ви створюєте для списку кілька типів перегляду, як це пояснено в stackoverflow.com/a/26245463/3731795 ... Ви відстежуєте індекс, на який елемент розширюється, а решта елементів згортається в цей час . Тепер якщо (current_item_index == розширений_item_index) {return VIEW_TYPE_EXPANDED} else {reutrn VIEW_TYPE_COLLAPSED}
penduDev
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.