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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With