android - Efecto deslizante hacia abajo en ExpandableListView
slidedown slideup (5)
¿Es posible tener un buen efecto de deslizamiento hacia arriba / abajo al expandir / contraer un elemento de un ExpandableListView?
Si es así, ¿cómo?
Gracias por adelantado.
Así que este es un duplicado completo de this . En resumen, utilicé una lista regular, realicé mi propia vista desplegable, utilicé una animación desplegable personalizada y cumplí con éxito (mira el enlace para obtener una descripción más detallada).
Edición: Guía paso a paso:
Primero creo el 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>
La animación para 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;
}
}
Luego, dentro de mi adaptador (por supuesto, agregará más sintaxis, y si desea que el menú desplegable no se cierre cuando esté fuera de la vista en la lista, también debe recordar esto en el soporte 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 tus listas en el artículo:
@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 sea la mejor manera de hacerlo, pero esto es lo que funcionó para mí.
Edición : Hay una solución diferente de DevBytes en youtube que se puede ver here .
Expand / collapse no funciona con el código desde aquí: https://github.com/tjerkw/Android-SlideExpandableListView porque OnItemExpandCollapseListener expandCollapseListener
de AbstractSlideExpandableListAdapter
es null
; se llama al método notifiyExpandCollapseListener
cuando se inicia la animación, pero el oyente es null
porque: tiene ActionSlideExpandableListView
:
ActionSlideExpandableListView lv = (ActionSlideExpandableListView) findViewById(R.id.list_view);
SlideExpandableListAdapter slideAdapter = new SlideExpandableListAdapter(adapter,R.id.expandable_toggle_button, R.id.expandable);
y configura el adaptador: lv.setAdapter(slideAdapter);
que llama al método setAdapter
desde SlideExpandableListView
y allí se crea una nueva instancia de SlideExpandableListAdapter
.
Cambié así: el método setAdapter
de ActionSlideExpandableListView
toma como parámetro AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener
que se pasa al método SlideExpandableListView
desde SlideExpandableListView
. Allí cuando creo SlideExpandableListAdapter
también paso este escucha:
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);
}
La implementación de Warpzit definitivamente funciona, sin embargo, es inutilizable si necesita apoyar a grupos con muchos niños (digamos 100), ya que no utilizará la estructura optimizada de ListView (es decir, la reutilización / reciclaje de vistas infantiles). ). En cambio, terminé extendiendo ExpandableListView para crear un AnimatedExpandableListView que usa la técnica que describí here . Al hacerlo, AnimatedExpandableListView puede animar la expansión del grupo mientras sigue ofreciendo el mejor rendimiento. Echar un vistazo.
La respuesta señalada por Warpzit es correcta. Utilicé este enfoque para proporcionar una biblioteca que puede incrustar fácilmente en su aplicación sin tener que saber cómo funciona realmente:
https://github.com/tjerkw/Android-SlideExpandableListView
Se puede leer más sobre esto en esta publicación del blog: http://tjerktech.wordpress.com/2012/06/23/an-emerging-android-ui-pattern-for-contextual-actions/
Prueba esto en 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;
}
});