Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slide down effect on ExpandableListView

Is it possible to have a nice slide up/down effect when expanding/collapsing an item of a ExpandableListView?

If yes, how?

Thanks in advance.

like image 865
thomaus Avatar asked Jan 08 '12 18:01

thomaus


1 Answers

So This is a complete duplicate of this. In short, I used a regular list, made my own dropdown view, used a custom drop down animation and voila success (look at link for more description).

Edit: Step by step guide:

First I create the 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> 

The animation for dropdown is following:

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

Then inside my adapter (you'll ofcourse add more syntax, and if you want the dropdown to not close when out of sight in the list, you need to remember this in the holder with some kind of parameter as well):

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

Then the magic happens in your lists 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); } 

Final comment: I'm not sure this is the best way of doing it but this is what worked for me.

Edit: There is a different solution by DevBytes on youtube that can be viewed here.

like image 179
Warpzit Avatar answered Sep 23 '22 16:09

Warpzit