Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve smooth expand/collapse animation

I'm referring the expand / collapse animation code found here.

Android: Expand/collapse animation

Although it works, it doesn't do the job well. The animation isn't smooth.

I do some logging in the code.

public static void expand(final View v) {     v.measure(MeasureSpec.makeMeasureSpec(((View)v.getParent()).getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(1024, MeasureSpec.AT_MOST));     final int targtetHeight = v.getMeasuredHeight();      v.getLayoutParams().height = 0;     v.setVisibility(View.VISIBLE);     Animation a = new Animation()     {         @Override         protected void applyTransformation(float interpolatedTime, Transformation t) {             v.getLayoutParams().height = interpolatedTime == 1                     ? LayoutParams.WRAP_CONTENT                     : (int)(targtetHeight * interpolatedTime);             Log.i("CHEOK", "E v.getLayoutParams().height = " + v.getLayoutParams().height);             v.requestLayout();         } 

The following log message is printed.

10-09 12:29:58.808: I/CHEOK(7874): E v.getLayoutParams().height = 0 10-09 12:29:58.808: I/CHEOK(7874): E v.getLayoutParams().height = 0 10-09 12:29:58.918: I/CHEOK(7874): E v.getLayoutParams().height = 11 10-09 12:29:59.015: I/CHEOK(7874): E v.getLayoutParams().height = 35 10-09 12:29:59.117: I/CHEOK(7874): E v.getLayoutParams().height = 64 10-09 12:29:59.215: I/CHEOK(7874): E v.getLayoutParams().height = 85 10-09 12:29:59.316: I/CHEOK(7874): E v.getLayoutParams().height = -2 10-09 12:29:59.406: I/CHEOK(7874): E v.getLayoutParams().height = -2 

New height occur every ~100ms. So, the FPS of the animation is around 10fps

I want to see what is the ideal animation frame rate. I remove the v.requestLayout();. I get the following logging.

10-09 12:32:06.547: I/CHEOK(8926): E v.getLayoutParams().height = 0 10-09 12:32:06.562: I/CHEOK(8926): E v.getLayoutParams().height = 0 10-09 12:32:06.605: I/CHEOK(8926): E v.getLayoutParams().height = 4 10-09 12:32:06.625: I/CHEOK(8926): E v.getLayoutParams().height = 7 10-09 12:32:06.644: I/CHEOK(8926): E v.getLayoutParams().height = 10 10-09 12:32:06.664: I/CHEOK(8926): E v.getLayoutParams().height = 14 10-09 12:32:06.679: I/CHEOK(8926): E v.getLayoutParams().height = 18 10-09 12:32:06.699: I/CHEOK(8926): E v.getLayoutParams().height = 22 10-09 12:32:06.715: I/CHEOK(8926): E v.getLayoutParams().height = 27 10-09 12:32:06.734: I/CHEOK(8926): E v.getLayoutParams().height = 32 10-09 12:32:06.750: I/CHEOK(8926): E v.getLayoutParams().height = 37 10-09 12:32:06.769: I/CHEOK(8926): E v.getLayoutParams().height = 42 10-09 12:32:06.785: I/CHEOK(8926): E v.getLayoutParams().height = 47 10-09 12:32:06.804: I/CHEOK(8926): E v.getLayoutParams().height = 52 10-09 12:32:06.828: I/CHEOK(8926): E v.getLayoutParams().height = 59 10-09 12:32:06.840: I/CHEOK(8926): E v.getLayoutParams().height = 62 10-09 12:32:06.863: I/CHEOK(8926): E v.getLayoutParams().height = 67 10-09 12:32:06.879: I/CHEOK(8926): E v.getLayoutParams().height = 71 10-09 12:32:06.894: I/CHEOK(8926): E v.getLayoutParams().height = 75 10-09 12:32:06.910: I/CHEOK(8926): E v.getLayoutParams().height = 79 10-09 12:32:06.929: I/CHEOK(8926): E v.getLayoutParams().height = 82 10-09 12:32:06.945: I/CHEOK(8926): E v.getLayoutParams().height = 85 10-09 12:32:06.965: I/CHEOK(8926): E v.getLayoutParams().height = 88 10-09 12:32:06.984: I/CHEOK(8926): E v.getLayoutParams().height = 89 10-09 12:32:07.000: I/CHEOK(8926): E v.getLayoutParams().height = 91 10-09 12:32:07.019: I/CHEOK(8926): E v.getLayoutParams().height = 91 10-09 12:32:07.039: I/CHEOK(8926): E v.getLayoutParams().height = -2 10-09 12:32:07.054: I/CHEOK(8926): E v.getLayoutParams().height = -2 

New height occur every ~20ms. So, the FPS of the animation is around 50fps

Of course, I can't just remove requestLayout, as UI won't updated on screen.

I was wondering, is there any improvement can be done, to achieve animation FPS closed to 50fps? I had seen some commercial product with smooth Expand/collapse example. So, I think this is something achievable. Just that, I'm not sure exactly how.

My layout code is as followed :

        <LinearLayout             android:clickable="true"             android:id="@+id/chart_linear_layout"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_marginTop="10dp"             android:layout_marginLeft="10dp"             android:layout_marginRight="10dp"             android:background="@drawable/dummy"             android:orientation="vertical">             <LinearLayout                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                 android:layout_margin="10dp"                 android:orientation="horizontal">                 <TextView                     android:layout_width="0dp"                     android:width="0dp"                     android:layout_weight="0.6"                     android:layout_height="wrap_content"                     android:gravity="left"                     android:textSize="20sp"                      android:textColor="#ff000000"                     android:text="Summary chart" />                 <TextView                     android:id="@+id/chart_price_text_view"                     android:layout_width="0dp"                     android:width="0dp"                     android:layout_weight="0.4"                     android:layout_height="wrap_content"                     android:gravity="right"                     android:textSize="20sp"                      android:textColor="#ffF76D3C"                     android:text="$2.99" />              </LinearLayout>             <TextView                 android:visibility="gone"                 android:id="@+id/chart_description_text_view"                 android:layout_marginLeft="10dp"                 android:layout_marginRight="10dp"                 android:layout_marginBottom="10dp"                 android:layout_width="match_parent"                 android:layout_height="wrap_content"                          android:text="@string/currency_exchange_description"                 android:textColor="#ff626262"                 android:textSize="15sp" />                          </LinearLayout> 

I wish to perform smooth animation on chart_description_text_view from

Collapsing (During app startup)

enter image description here

Expanding (When user taps on it)

enter image description here

One of the "role models" I can think of is https://play.google.com/store/apps/details?id=ch.bitspin.timely. Try to invoke the below dialog from its Shop menu item. You will realize how smooth their animation is. Not exactly sure how they achieve that.

enter image description here

like image 422
Cheok Yan Cheng Avatar asked Oct 09 '13 04:10

Cheok Yan Cheng


1 Answers

You can do Smooth Animation of View this way:

public class ViewAnimationUtils {      public static void expand(final View v) {         v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);         final int targtetHeight = v.getMeasuredHeight();          v.getLayoutParams().height = 0;         v.setVisibility(View.VISIBLE);         Animation a = new Animation()         {             @Override             protected void applyTransformation(float interpolatedTime, Transformation t) {                 v.getLayoutParams().height = interpolatedTime == 1                         ? LayoutParams.WRAP_CONTENT                         : (int)(targtetHeight * interpolatedTime);                 v.requestLayout();             }              @Override             public boolean willChangeBounds() {                 return true;             }         };          a.setDuration((int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density));         v.startAnimation(a);     }      public static void collapse(final View v) {         final int initialHeight = v.getMeasuredHeight();          Animation a = new Animation()         {             @Override             protected void applyTransformation(float interpolatedTime, Transformation t) {                 if(interpolatedTime == 1){                     v.setVisibility(View.GONE);                 }else{                     v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);                     v.requestLayout();                 }             }              @Override             public boolean willChangeBounds() {                 return true;             }         };          a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));         v.startAnimation(a);     } } 

Hope it will help you.

like image 169
Hiren Patel Avatar answered Sep 20 '22 23:09

Hiren Patel