Deslice el efecto hacia abajo en ExpandableListView

¿Es posible tener una buena diapositiva arriba / abajo efecto al expandir / colapsar un elemento de un ExpandableListView?

Si es así, ¿cómo?

Gracias por adelantado.

    Así que esto es un duplicado completo de esto . En resumen, he utilizado una lista regular, he hecho mi propia vista desplegable, utiliza una caída personalizada de animación y éxito voila (mira el enlace para más descripción).

    Editar: Guía paso a paso:

    Primero creo el list_row de xml:

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

    La animación de la lista desplegable es la siguiente:

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

    Entonces dentro de mi adaptador (por supuesto, agregue más sintaxis, y si desea que la lista desplegable no cierre cuando está fuera de la vista en la lista, debe recordar esto en el titular con algún tipo de parámetro)

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

    Entonces la magia sucede en sus listas 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); } 

    Comentario final: No estoy seguro de que esta es la mejor manera de hacerlo, pero esto es lo que funcionó para mí.

    Editar : Hay una solución diferente por DevBytes en youtube que se puede ver aquí .

    La advertencia señalada por Warpzit es correcta. He utilizado este enfoque para proporcionar una biblioteca que se puede integrar fácilmente en su aplicación sin tener que saber cómo funciona realmente:

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

    Más sobre esto se puede leer en esta entrada del blog: http://tjerktech.wordpress.com/2012/06/23/an-emerging-android-ui-pattern-for-contextual-actions/

    La implementación de Warpzit definitivamente funciona, sin embargo es inutilizable si necesitas apoyar a grupos con muchos niños (digamos 100) ya que no vas a hacer uso de la estructura optimizada de ListView (es decir, la reutilización / reciclado de vistas de niños ). En su lugar, terminé extendiendo ExpandableListView para crear un AnimatedExpandableListView que utiliza la técnica que he descrito aquí . Al hacer esto, AnimatedExpandableListView puede animar la expansión de grupo mientras sigue ofreciendo un rendimiento superior. Echar un vistazo.

    La expansión / colapso no funciona con el código de aquí: https://github.com/tjerkw/Android-SlideExpandableListView porque OnItemExpandCollapseListener expandCollapseListener de AbstractSlideExpandableListAdapter es null ; El método notifiyExpandCollapseListener se llama cuando se inicia la animación, pero el oyente es null porque: tiene el ActionSlideExpandableListView :

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

    Y se establece el adaptador: lv.setAdapter(slideAdapter); Que llama al método setAdapter de SlideExpandableListView y allí se crea una nueva instancia de SlideExpandableListAdapter .

    He cambiado de esta manera: método setAdapter de ActionSlideExpandableListView toma como un parámetro también AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener que se pasa al método SlideExpandableListView de SlideExpandableListView . Allí cuando creo SlideExpandableListAdapter paso también este oyente:

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

    Prueba esto en la clase 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; } }); 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.