diff --git a/android/widgets/src/main/java/org/nativescript/widgets/AnimatorHelper.java b/android/widgets/src/main/java/org/nativescript/widgets/AnimatorHelper.java new file mode 100644 index 000000000..3dfaf0708 --- /dev/null +++ b/android/widgets/src/main/java/org/nativescript/widgets/AnimatorHelper.java @@ -0,0 +1,61 @@ +package org.nativescript.widgets; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; + +class AnimatorHelper { + static final int version = android.os.Build.VERSION.SDK_INT; + static final int exitFakeResourceId = -20; + + static Animator createDummyAnimator(long duration) { + float[] alphaValues = new float[2]; + alphaValues[0] = 1; + alphaValues[1] = 1; + + Animator animator = ObjectAnimator.ofFloat(null, "alpha", alphaValues); + if (duration > 0) { + animator.setDuration(duration); + } + + return animator; + } + + static long getTotalDuration(Animator animator) { + if (animator instanceof AnimatorSet) { + return getAnimatorSetTotalDuration((AnimatorSet)animator); + } else { + return getAnimatorTotalDuration(animator); + } + } + + static long getAnimatorTotalDuration(Animator animator) { + long totalDuration; + if (version >= 24) { + totalDuration = animator.getTotalDuration(); + } else { + long duration = animator.getDuration(); + if (duration == Animator.DURATION_INFINITE) { + totalDuration = Animator.DURATION_INFINITE; + } else { + totalDuration = animator.getStartDelay() + duration; + } + } + + return totalDuration; + } + + static long getAnimatorSetTotalDuration(AnimatorSet animatorSet) { + long totalDuration = 0; + if (version >= 24) { + totalDuration = animatorSet.getTotalDuration(); + } else { + // TODO: this is only meaningful for "playTogether" animators + for (Animator animator: animatorSet.getChildAnimations()) { + totalDuration = Math.max(totalDuration, getTotalDuration(animator)); + } + } + + return totalDuration; + } +} diff --git a/android/widgets/src/main/java/org/nativescript/widgets/FragmentBase.java b/android/widgets/src/main/java/org/nativescript/widgets/FragmentBase.java new file mode 100644 index 000000000..66873bde9 --- /dev/null +++ b/android/widgets/src/main/java/org/nativescript/widgets/FragmentBase.java @@ -0,0 +1,36 @@ +package org.nativescript.widgets; + +import android.animation.Animator; +import android.support.v4.app.Fragment; + +public abstract class FragmentBase extends Fragment { + + @Override + public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { + // [nested frames / fragments] apply dummy animator to the nested fragment with + // the same duration as the exit animator of the removing parent fragment to work around + // https://code.google.com/p/android/issues/detail?id=55228 (child fragments disappear + // when parent fragment is removed as all children are first removed from parent) + if (!enter) { + Fragment removingParentFragment = this.getRemovingParentFragment(); + if (removingParentFragment != null) { + Animator parentAnimator = removingParentFragment.onCreateAnimator(transit, enter, AnimatorHelper.exitFakeResourceId); + if (parentAnimator != null) { + long duration = AnimatorHelper.getTotalDuration(parentAnimator); + return AnimatorHelper.createDummyAnimator(duration); + } + } + } + + return super.onCreateAnimator(transit, enter, nextAnim); + } + + public Fragment getRemovingParentFragment() { + Fragment parentFragment = this.getParentFragment(); + while (parentFragment != null && !parentFragment.isRemoving()) { + parentFragment = parentFragment.getParentFragment(); + } + + return parentFragment; + } +}