Эффект слайда вниз на ExpandableListView

Возможно ли иметь приятный эффект скольжения вверх/вниз при развертывании/сворачивании элемента ExpandableListView?

Если да, то как?

Заранее спасибо.


person thomaus    schedule 08.01.2012    source источник
comment
Возможно, есть простой способ просто замедлить скорость эффекта расширения для ExpandableListView. Есть один способ???   -  person thomaus    schedule 10.01.2012
comment
Мне одному интересно как этого добиться????   -  person thomaus    schedule 10.01.2012
comment
Вы нашли какое-нибудь решение? Спасибо.   -  person user430926    schedule 02.04.2012
comment
Нет, я не. Думаю, нам придется для Android реализовать симпатичный виджет. ;-)   -  person thomaus    schedule 16.04.2012
comment
Получили ли вы какое-либо решение для расширяемого списка?   -  person Alex Chengalan    schedule 08.05.2013


Ответы (6)


Итак, это полная копия this. Короче говоря, я использовал обычный список, создал свой собственный выпадающий список, использовал пользовательскую анимацию выпадающего списка и вуаля, успех (см. ссылку для более подробного описания).

Изменить: пошаговое руководство:

Сначала я создаю xml list_row:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/row_parent"
    android:orientation="vertical">
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/row_simple_parent"
        >
    <View
        android:id="@+id/row_simple_parent_invis_cover"
        android:visibility="gone"
        android:layout_height="something that fills out your content"
        android:layout_width="match_parent"
        android:background="@android:color/transparent"/>
    </RelativeLayout>

    <!-- Dropdown -->
    <RelativeLayout 
        android:id="@+id/row_dropdown"
        android:layout_height="wrap_content"
        android:layout_width="match_parent">
    </RelativeLayout>
</LinearLayout>

Анимация раскрывающегося списка следующая:

import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * Class for handling collapse and expand animations.
 * @author Esben Gaarsmand
 *
 */
public class ExpandCollapseAnimation extends Animation {
    private View mAnimatedView;
    private int mEndHeight;
    private int mStartVisibility;

    /**
     * Initializes expand collapse animation. If the passed view is invisible/gone the animation will be a drop down, 
     * if it is visible the animation will be collapse from bottom
     * @param view The view to animate
     * @param duration
     */ 
    public ExpandCollapseAnimation(View view, int duration) {
        setDuration(duration);
        mAnimatedView = view;
        mEndHeight = mAnimatedView.getLayoutParams().height;
        mStartVisibility = mAnimatedView.getVisibility();
        if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
            mAnimatedView.setVisibility(View.VISIBLE);
            mAnimatedView.getLayoutParams().height = 0;
        }
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        if (interpolatedTime < 1.0f) {
            if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
                mAnimatedView.getLayoutParams().height = (int) (mEndHeight * interpolatedTime);
            } else {
                mAnimatedView.getLayoutParams().height = mEndHeight - (int) (mEndHeight * interpolatedTime);
            }
            mAnimatedView.requestLayout();
        } else {
            if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
                mAnimatedView.getLayoutParams().height = mEndHeight;
                mAnimatedView.requestLayout();
            } else {
                mAnimatedView.getLayoutParams().height = 0;
                mAnimatedView.setVisibility(View.GONE);
                mAnimatedView.requestLayout();
                mAnimatedView.getLayoutParams().height = mEndHeight;
            }
        }
    }

    /**
     * This methode can be used to calculate the height and set itm for views with wrap_content as height. 
     * This should be done before ExpandCollapseAnimation is created.
     * @param activity
     * @param view
     */
    public static void setHeightForWrapContent(Activity activity, View view) {
        DisplayMetrics metrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

        int screenWidth = metrics.widthPixels;

        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);

        view.measure(widthMeasureSpec, heightMeasureSpec);
        int height = view.getMeasuredHeight();
        view.getLayoutParams().height = height;
    }
}

Затем внутри моего адаптера (вы, конечно, добавите больше синтаксиса, и если вы хотите, чтобы выпадающий список не закрывался, когда его не видно в списке, вам нужно запомнить это в держателе с каким-то параметром):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    if(convertView == null) {
        // setup holder
        holder = new ViewHolder();
        convertView = mInflater.inflate(R.layout.list_row, null);
        holder.mDropDown = convertView.findViewById(R.id.row_dropdown);
        convertView.setTag(holder);
    } else {
        // get existing row view
        holder = (ViewHolder) convertView.getTag();
    }
    holder.mDropDown.setVisibility(View.GONE);
    return convertView;
}

Затем в ваших списках onItemClick происходит волшебство:

@Override
public void onListItemClick(ListView list, View view, int position, long id) {
    final ListItem item = (ListItem) list.getAdapter().getItem(position);
    // set dropdown data
    ViewHolder holder = (ViewHolder) view.getTag();
    final View dropDown = holder.mDropDown;

    // set click close on top part of view, this is so you can click the view
    // and it can close or whatever, if you start to add buttons etc. you'll loose
    // the ability to click the view until you set the dropdown view to gone again.
    final View simpleView = view.findViewById(R.id.row_simple_parent_invis_cover);
    simpleView.setVisibility(View.VISIBLE);

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 0) {
                // first we measure height, we need to do this because we used wrap_content
                // if we use a fixed height we could just pass that in px.
                ExpandCollapseAnimation.setHeightForWrapContent(getActivity(), dropDown);
                ExpandCollapseAnimation expandAni = new ExpandCollapseAnimation(dropDown, DROP_DOWN_TIME);
                dropDown.startAnimation(expandAni);

                Message newMsg = new Message();

            } else if(msg.what == 1) {
                ExpandCollapseAnimation expandAni = new ExpandCollapseAnimation(dropDown, DROP_DOWN_TIME);
                dropDown.startAnimation(expandAni);

                simpleView.setOnClickListener(null);
                simpleView.setVisibility(View.GONE);
            }
        }
    };

    simpleView.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            handler.sendEmptyMessage(1);
        }
    });

    // start drop down animation
    handler.sendEmptyMessage(0);
}

Заключительный комментарий: я не уверен, что это лучший способ сделать это, но это сработало для меня.

Изменить. На YouTube есть другое решение от DevBytes, которое можно просмотреть здесь.

person Warpzit    schedule 18.04.2012
comment
@Kermia Я сделаю это позже. Не уверен, что опубликую это здесь/в другом посте или в обоих =/. Поскольку вы просите об этом, я опубликую это здесь, я думаю. - person Warpzit; 20.04.2012
comment
Привет, я использую ваш пример, чтобы сделать свою собственную анимацию, но я не знаю, что делает postDropHandler, и не знаю, как это реализовано, если это возможно. Спасибо - person Alvin Baena; 13.05.2012
comment
Я почти уверен, что его наследие от моей собственной реализации позже сделает очистку кода. Я использовал его, чтобы сказать, когда анимация закончилась, чтобы я мог что-то сделать в конце анимации. - person Warpzit; 14.05.2012
comment
Я немного запутался (в основном потому, что я пытался реализовать код в вашем ответе в своем собственном приложении для тестирования): методы onListItemClick и getView предназначены для ListView, но здесь мы используем ExpandableListView. Так зачем эти методы ListView? Кроме того, какой у вас ViewHolder класс? - person gosr; 23.06.2012
comment
Привет, Warpzit, я использовал этот подход в библиотеке, которая решает эту проблему раз и навсегда: библиотека Android-SlideExpandableListView: github .com/tjerkw/Android-SlideExpandableListView Подробнее об этом можно прочитать в этом сообщении блога: tjerktech.wordpress.com/2012/06/23/ - person TjerkW; 23.06.2012
comment
Это не поможет, если мы хотим анимировать расширение группы в ExpandableListView. Это решение хорошее, но решает другой вопрос. - person hadi; 03.08.2013
comment
@RishabhSrivastava какая часть? Это сработало для многих других, поэтому вы должны быть немного более конкретными. - person Warpzit; 04.09.2013
comment
он показывает пустой ListView... У меня есть TextView в качестве элемента списка, и я хочу отображать три кнопки со скользящей анимацией, если элемент нажат, где должен быть написан xml-код кнопок? и где установить текст для ListItem?? - person Rishabh Srivastava; 04.09.2013
comment
@RishabhSrivastava все виды, которые должны отображаться после щелчка раскрывающегося списка, должны быть помещены в RelativeLayout под комментарием: ‹!-- Раскрывающийся список --›. Насчет установки текста, это происходит в методе getView(), но это стандартная штука для Android. - person Warpzit; 04.09.2013
comment
я попробовал, но ничего не произошло, наконец, я нашел этот невероятный пример github.com/Udinic/SmallExamples /tree/master/, который решил мою проблему... коротко и просто... Кстати, большое спасибо @Warpzit - person Rishabh Srivastava; 04.09.2013
comment
@warpzit: в вашем списке отображается несколько скользящих элементов списка, можно ли закрыть последний скользящий вид и открыть новый слайдер. внутри onitemclick().? - person user755; 27.09.2013
comment
любая идея, как раскрывающийся список не закрывается, когда он вне поля зрения - person user755; 27.09.2013
comment
@user2439755 user2439755 Я уже объяснил это: Затем внутри моего адаптера (вы, конечно, добавите больше синтаксиса, и если вы хотите, чтобы раскрывающийся список не закрывался, когда его не видно в списке, вам нужно запомнить это в держателе каким-то параметра также): - person Warpzit; 27.09.2013

Ответ, указанный Warpzit, верен. Я использовал этот подход, чтобы предоставить библиотеку, которую вы можете легко встроить в свое приложение, не зная, как она на самом деле работает:

https://github.com/tjerkw/Android-SlideExpandableListView

Подробнее об этом можно прочитать в этом сообщении блога: http://tjerktech.wordpress.com/2012/06/23/an-emerging-android-ui-pattern-for-contextual-actions/

person TjerkW    schedule 23.06.2012

Реализация Warpzit определенно работает, однако ее нельзя использовать, если вам нужно поддерживать группы с большим количеством дочерних элементов (скажем, 100), поскольку вы не будете использовать оптимизированную структуру ListView (т. е. повторное использование/переработка дочерних представлений). ). Вместо этого я расширил ExpandableListView, чтобы создать AnimatedExpandableListView, использующий метод, который я описал здесь. Таким образом, AnimatedExpandableListView может анимировать расширение группы, сохраняя при этом максимальную производительность. Посмотрите.

person idunnololz    schedule 01.04.2014

Развертывание/свертывание не работает с кодом отсюда: https://github.com/tjerkw/Android-SlideExpandableListView, потому что OnItemExpandCollapseListener expandCollapseListener из AbstractSlideExpandableListAdapter равно null; метод notifiyExpandCollapseListener вызывается при запуске анимации, но слушателем является null, потому что: у вас есть ActionSlideExpandableListView:

ActionSlideExpandableListView lv = (ActionSlideExpandableListView) findViewById(R.id.list_view);
SlideExpandableListAdapter slideAdapter = new SlideExpandableListAdapter(adapter,R.id.expandable_toggle_button, R.id.expandable);

и вы устанавливаете адаптер: lv.setAdapter(slideAdapter); который вызывает метод setAdapter из SlideExpandableListView и там создается новый экземпляр SlideExpandableListAdapter.

Я изменил так: метод setAdapter из ActionSlideExpandableListView принимает в качестве параметра также AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener, который передается в метод setAdapter из SlideExpandableListView. Там, когда я создаю SlideExpandableListAdapter, я также передаю этот слушатель:

 public void setAdapter(ListAdapter adapter, AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener expandCollapseListener) {
        this.adapter = new SlideExpandableListAdapter(adapter, expandCollapseListener);
        super.setAdapter(this.adapter);
    }

    public SlideExpandableListAdapter(ListAdapter wrapped, OnItemExpandCollapseListener expandCollapseListener) {
        this(wrapped, R.id.expandable_toggle_button, R.id.expandable);
        setItemExpandCollapseListener(expandCollapseListener);
    }
person Paul    schedule 03.09.2014

Если вы уже используя BaseExpandableListAdapter, который расширяет ExpandableListAdapter. Таким образом, нет необходимости использовать модификацию ListView.

Вам нужно только создать подкласс AnimatedExpandableListAdapter вместо BaseExpandableListAdapter и AnimatedExpandableListView вместо ExpandableListView.

Вместо @Override getChildrenCount просто используйте @Override getRealChildrenCount. Сделайте то же самое для @Override getChildView,, используя вместо него @Override getRealChildView.

Затем вы используете анимацию следующим образом:

    expandableListView.setOnGroupClickListener(new AnimatedExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            if (expandableListView.isGroupExpanded(groupPosition))
                expandableListView.collapseGroupWithAnimation(groupPosition);
            else
                expandableListView.expandGroupWithAnimation(groupPosition);
            return true;
        }

    });

Еще одна деталь заключается в том, что в вашем XML-файле макета вам нужно ссылаться на AnimatedExpandableListView, а не на ExpandableListView:

<com.your.package.project.class.location.AnimatedExpandableListView
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Пример кода в проекте и комментарии к классу AnimatedExpandableListView очень полезны, если вам нужна дополнительная помощь.

person neowinston    schedule 25.05.2019

Попробуйте это в классе Java

       expListView.setAdapter(listAdapter);
    expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
        int previousGroup = -1;

        @Override
        public void onGroupExpand(int groupPosition) {
            if(groupPosition != previousGroup)
                expListView.collapseGroup(previousGroup);
            previousGroup = groupPosition;
        }
    });
person user3145931    schedule 18.01.2014