diff --git a/fragment/src/main/java/com/marksalpeter/fragment/ContractFragment.java b/fragment/src/main/java/com/marksalpeter/fragment/ContractFragment.java index 065ed07..53faeeb 100644 --- a/fragment/src/main/java/com/marksalpeter/fragment/ContractFragment.java +++ b/fragment/src/main/java/com/marksalpeter/fragment/ContractFragment.java @@ -1,24 +1,23 @@ package com.marksalpeter.fragment; import android.app.Activity; -import android.app.Fragment; import java.lang.reflect.ParameterizedType; /** - * ContractFragment is a fragment whos parent fragment or parent activity must implement an interface - * Created by Mark Salpeter. Original concepts taken from Jake Thwarton + * ContractFragment is a fragment whos parent fragment or parent activity must implement the interface T + * Created by Mark Salpeter. Original concepts taken from Jake Wharton * see https://gist.github.com/JakeWharton/2621173 */ -public abstract class ContractFragment extends ChildFragment { +public abstract class ContractFragment extends Fragment { - public final static String TAG = ChildFragment.class.getSimpleName(); + public final static String TAG = Fragment.class.getSimpleName(); private T mContract; @Override public void onAttach(Activity activity) { - Fragment parentFragment = getParentFragment(); + android.app.Fragment parentFragment = getParentFragment(); if (parentFragment != null && isContractImplemented(parentFragment.getClass())) { mContract = (T) getParentFragment(); } else if (isContractImplemented(activity.getClass())) { @@ -44,6 +43,10 @@ public void onDetach() { mContract = null; } + /** + * getContract returns the interface of type T that must be + * implemented on either the parent fragment or the parent activity + */ public final T getContract() { return mContract; } diff --git a/fragment/src/main/java/com/marksalpeter/fragment/ChildFragment.java b/fragment/src/main/java/com/marksalpeter/fragment/Fragment.java similarity index 52% rename from fragment/src/main/java/com/marksalpeter/fragment/ChildFragment.java rename to fragment/src/main/java/com/marksalpeter/fragment/Fragment.java index 6dd8d3b..bea5e5b 100644 --- a/fragment/src/main/java/com/marksalpeter/fragment/ChildFragment.java +++ b/fragment/src/main/java/com/marksalpeter/fragment/Fragment.java @@ -3,20 +3,20 @@ import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.ValueAnimator; -import android.app.Fragment; import android.content.res.Resources; +import android.util.Log; import java.lang.reflect.Field; /** - * ChildFragment fixes a critical view bug where child fragments are sometimes removed from the screen + * Fragment fixes an animation bug where child fragments are sometimes removed from the screen * before their parents are removed from the screen. * More Info: http://stackoverflow.com/questions/14900738/nested-fragments-disappear-during-transition-animation * Created by Mark Salpeter on 9/20/16. */ -public class ChildFragment extends Fragment { +public class Fragment extends android.app.Fragment { - public static String TAG = ChildFragment.class.getSimpleName(); + public static String TAG = Fragment.class.getSimpleName(); /** * sDefaultChildAnimationDuration is an arbitrary, but reasonable transition duration we can use if @@ -24,34 +24,29 @@ public class ChildFragment extends Fragment { */ private static final int sDefaultChildAnimationDuration = 1000; - @Override public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { - // if a child fragment is being removed because its parent is being removed - // return a fake animator that lasts the duration of the parent's animator - Fragment removingParentFragment = getRemovingParent(getParentFragment()); - if (!enter && removingParentFragment != null) { - // This is a workaround for the bug where child fragments disappear when - // the parent is removed (as all children are first removed from the parent) - // See https://code.google.com/p/android/issues/detail?id=55228 - long duration = getNextAnimatiorDuration(removingParentFragment); - return ValueAnimator.ofFloat(0, 1).setDuration(duration); + /** + * onCreateAnimator is overridden to fix the following animation bug: + * http://stackoverflow.com/questions/14900738/nested-fragments-disappear-during-transition-animation + */ + @Override public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { + if(!enter) { + android.app.Fragment removingParentFragment = getRemovingParentFragment(); + if (removingParentFragment != null) { + return ValueAnimator.ofFloat(0f, 1f).setDuration(getNextAnimatorDuration(removingParentFragment)); + } } - - // inflate the animator - Animator animator = null; - try { - animator = AnimatorInflater.loadAnimator(getActivity(), nextAnim); - } catch (Exception e) {} - - return animator; + return super.onCreateAnimator(transit, enter, nextAnim); } /** - * getRemovingParent returns the first fragment or parent fragment that is removing r null if it can't find one + * getRemovingParentFragment returns the first fragment or parent fragment that is removing r null if it can't find one */ - private static Fragment getRemovingParent(Fragment fragment) { + private android.app.Fragment getRemovingParentFragment() { + android.app.Fragment fragment = getParentFragment(); while (fragment != null) { if (fragment.isRemoving()) { + Log.v(TAG, fragment.toString() + " is removing"); return fragment; } fragment = fragment.getParentFragment(); @@ -63,21 +58,29 @@ private static Fragment getRemovingParent(Fragment fragment) { * getNextAnimationDuration returns the "mNextAnim" animators duration * TODO: this needs a bug fix, but its not mission critical unless people are adding fragment transition */ - private static long getNextAnimatiorDuration(Fragment fragment) { + private static long getNextAnimatorDuration(android.app.Fragment fragment) { try { // attempt to get the resource ID of the next animation that will be applied to the given fragment. - Field nextAnimField = Fragment.class.getDeclaredField("mNextAnim"); + Field nextAnimField = android.app.Fragment.class.getDeclaredField("mNextAnim"); nextAnimField.setAccessible(true); - int nextAnimResource = nextAnimField.getInt(fragment); + int nextAnimResourceID = nextAnimField.getInt(fragment); + + Log.v(TAG, "nextAnimResourceID: " + nextAnimResourceID); + if (nextAnimResourceID < 1) { + return sDefaultChildAnimationDuration; + } // load the animator - Animator nextAnim = AnimatorInflater.loadAnimator(fragment.getActivity(), nextAnimResource); + Animator nextAnim = AnimatorInflater.loadAnimator(fragment.getActivity(), nextAnimResourceID); + + Log.v(TAG, "nextAnim.getDuration(): " + nextAnim.getDuration()); // return its duration return(nextAnim == null || nextAnim.getDuration() < 0) ? sDefaultChildAnimationDuration : nextAnim.getDuration(); } catch (NoSuchFieldException|IllegalAccessException|Resources.NotFoundException ex) { + Log.e(TAG, ex.getMessage(), ex); return sDefaultChildAnimationDuration; } }