How to achieve smooth animation of fragment transactions on Android

I mainly worked with iOS and got used to very smooth and smooth screen change animations. I am currently working on an Android application and cannot get a fragment transaction for the whole life to smoothly add / replace a fragment.

My setup is this: MainActivity has a FrameLayout for my xml, which I immediately load FragmentA into MainActivity OnCreate . Then my application replaces MainActivity FrameLayout with FragmentB , FragmentC , ect. Thus, my entire application has 1 activity.

In the button clicks, I call the following to add / replace the current fragment:

  getFragmentManager() .beginTransaction() .setCustomAnimations(R.animator.slide_in, android.R.animator.fade_out, android.R.animator.fade_in, R.animator.slide_out) .addToBackStack(null) .add(R.id.fragment_1, fragment) .commit(); 

slide_in.xml looks like (slide_out.xml is clearly the opposite):

  <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:interpolator="@android:interpolator/linear" android:propertyName="xFraction" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="0" android:duration="@android:integer/config_shortAnimTime" /> </set> 

Insertion and shutdown I am an xFraction animation that I have subclassed LinearLayout to do this:

 public class SlidingLinearLayout extends LinearLayout { private float yFraction = 0; private float xFraction = 0; public SlidingLinearLayout(Context context) { super(context); } public SlidingLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SlidingLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } private ViewTreeObserver.OnPreDrawListener preDrawListener = null; public void setYFraction(float fraction) { this.yFraction = fraction; if (getHeight() == 0) { if (preDrawListener == null) { preDrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(preDrawListener); setYFraction(yFraction); return true; } }; getViewTreeObserver().addOnPreDrawListener(preDrawListener); } return; } float translationY = getHeight() * fraction; setTranslationY(translationY); } public float getYFraction() { return this.yFraction; } public void setXFraction(float fraction) { this.xFraction = fraction; if (getWidth() == 0) { if (preDrawListener == null) { preDrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(preDrawListener); setXFraction(xFraction); return true; } }; getViewTreeObserver().addOnPreDrawListener(preDrawListener); } return; } float translationX = getWidth() * fraction; setTranslationX(translationX); } public float getxFraction() { return xFraction; } } 

So, my problem in most cases, when I initially clicked a button to add / replace a fragment, I do not get the animation, these are just pop-ups. However, more times than when I click the "Back" button, and a fragment appears from the back of the screen, the animation runs as expected. I feel this is an initialization issue when trying to revive. When a fragment is in memory and animated from the screen, it does it much better than when a new fragment is created, and then animated on the screen. I am curious if others have experienced this, and if so, how did they resolve it.

This is the annoyance that haunted my Android development experience, which I really would like to relax! Any help would be greatly appreciated. Thanks!

+6
source share
1 answer

In my experience, if a fragment does too much work with load, the system basically skips the input animation and just displays the fragment. In my case, the solution was to create an animation listener in onCreateAnimation to wait for the input animation to complete before doing the intense work that caused the skipped animation.

 @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if (nextAnim == 0) { return super.onCreateAnimation(transit, enter, nextAnim); } Animation anim = android.view.animation.AnimationUtils.loadAnimation(getContext(), nextAnim); anim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { // Do any process intensive work that can wait until after fragment has loaded } @Override public void onAnimationRepeat(Animation animation) {} }); return anim; } 
+1
source

Source: https://habr.com/ru/post/987771/


All Articles