Подтвердить что ты не робот

Android ExpandableListView с использованием анимации

Я использую

<ExpandableListView
     android:id="@+id/listView"
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
</ExpandableListView>

Я хочу добавить анимационный слайд для дочернего элемента, когда он включен. Итак, как я могу это сделать?

4b9b3361

Ответ 1

Окончательное обновление

Прошло довольно много времени с тех пор, как я написал этот ответ. С тех пор многое изменилось. Самое большое изменение - введение RecyclerView, что упрощает анимацию списка или сетки. Я настоятельно рекомендую переключиться на RecyclerView, если можно. Для тех, кто не может, я увижу, что я могу сделать для исправления ошибок для моей библиотеки.


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

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

Я расширил класс ExpandableListView и переопределил функции onCollapse и onExpand. Я также создал подкласс BaseExpandableListAdapter под названием AnimatedExpandableListAdapter. Внутри адаптера я переопределил функцию getChildView и сделал функцию final так, что функция не может быть снова переопределена. Вместо этого я предоставил другую функцию, называемую getRealChildView для подклассов, чтобы переопределить, чтобы обеспечить реальный дочерний вид. Затем я добавил в класс флаг анимации и сделал getChildView возвращением фиктивного представления, если был установлен флаг анимации, и реальный вид, если флаг не был установлен. Теперь со сценой я делаю следующее для onExpand:

  • Установите флаг анимации в адаптере и сообщите адаптеру, какая группа расширяется.
  • Вызов notifyDataSetChanged() (заставляет адаптер вызывать getChildView() для всех просмотров на экране).
  • Адаптер (в режиме анимации) затем создаст фиктивный вид для расширяющейся группы с начальной высотой 0. Адаптер затем получит реальные дочерние представления и передаст эти представления в фиктивный вид.
  • В представлении фиктивного типа начнутся рисовать реальные дочерние представления внутри собственной onDraw() функции.
  • Адаптер начнет цикл анимации, который расширит фиктивный вид до нужного размера. Он также установит прослушиватель анимации, чтобы он мог очистить флаг анимации после завершения анимации и также будет вызывать notifyDataSetChanged().

Наконец, со всем этим я смог не только получить желаемый эффект анимации, но и желаемую производительность, так как этот метод будет работать с группой с более чем 100 детьми.

Для коллапсирующей анимации нужно выполнить немного больше работы, чтобы все это было настроено и запущено. В частности, когда вы переопределяете onCollapse, вы не хотите вызывать родительскую функцию, так как она сбрасывает группу сразу, не оставляя вам никакой возможности воспроизвести анимацию. Вместо этого вы хотите вызвать super.onCollapse в конце анимации коллапса.

UPDATE:

Я провел некоторое время в эти выходные, чтобы переписать мою реализацию этого AnimatedExpandableListView, и я выпускаю источник с примером использования здесь: https://github.com/idunnololz/AnimatedExpandableListView/

Ответ 2

Решение @idunnololz отлично работает. однако я хотел бы добавить код, чтобы свернуть ранее расширенную группу.

private int previousGroup=-1;

    listView.setOnGroupClickListener(new OnGroupClickListener() {

        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            // We call collapseGroupWithAnimation(int) and
            // expandGroupWithAnimation(int) to animate group 
            // expansion/collapse.
            if (listView.isGroupExpanded(groupPosition)) {
                listView.collapseGroupWithAnimation(groupPosition);
                previousGroup=-1;
            } else {
                listView.expandGroupWithAnimation(groupPosition);
                if(previousGroup!=-1){
                    listView.collapseGroupWithAnimation(previousGroup); 
                }
                previousGroup=groupPosition;
            }

            return true;
        }

    });

Ответ 3

animateLayoutChanges adds auto-animation
<ExpandableListView
        android:animateLayoutChanges="true"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

Ответ 4

Решение @idunnololz работает отлично, но я испытал странное поведение с моей настраиваемой компоновкой для группы. Операция расширения не была выполнена должным образом, однако сбой был идеальным. Я импортировал его тестовый проект, и он работал отлично, поэтому я понял, что проблема связана с моей собственной компоновкой. Однако, когда я не смог найти проблему после некоторого расследования, я решил раскомментировать эти строки кода в своем AnimatedExpandListView:

       if (lastGroup && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            return expandGroup(groupPos, true);
        }

который вызвал проблему (мое приложение предназначено для Android 4.0 +).