Loading core/java/android/transition/TextChange.java→core/java/android/transition/ChangeText.java +38 −16 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.Map; * * @hide */ public class TextChange extends Transition { public class ChangeText extends Transition { private static final String LOG_TAG = "TextChange"; Loading Loading @@ -103,7 +103,7 @@ public class TextChange extends Transition { * transition is run. * @return this textChange object. */ public TextChange setChangeBehavior(int changeBehavior) { public ChangeText setChangeBehavior(int changeBehavior) { if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) { mChangeBehavior = changeBehavior; } Loading Loading @@ -179,10 +179,14 @@ public class TextChange extends Transition { startSelectionStart = startSelectionEnd = endSelectionStart = endSelectionEnd = -1; } if (!startText.equals(endText)) { final int startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR); final int endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR); if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(startText); if (view instanceof EditText) { setSelection(((EditText) view), startSelectionStart, startSelectionEnd); } } Animator anim; if (mChangeBehavior == CHANGE_BEHAVIOR_KEEP) { anim = ValueAnimator.ofFloat(0, 1); Loading @@ -200,8 +204,6 @@ public class TextChange extends Transition { }); } else { // Fade out start text final int startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR); final int endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR); ValueAnimator outAnim = null, inAnim = null; if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN || mChangeBehavior == CHANGE_BEHAVIOR_OUT) { Loading @@ -210,8 +212,8 @@ public class TextChange extends Transition { @Override public void onAnimationUpdate(ValueAnimator animation) { int currAlpha = (Integer) animation.getAnimatedValue(); view.setTextColor(currAlpha << 24 | Color.red(startColor) << 16 | Color.green(startColor) << 8 | Color.red(startColor)); view.setTextColor(currAlpha << 24 | startColor & 0xff0000 | startColor & 0xff00 | startColor & 0xff); } }); outAnim.addListener(new AnimatorListenerAdapter() { Loading @@ -225,6 +227,8 @@ public class TextChange extends Transition { endSelectionEnd); } } // restore opaque alpha and correct end color view.setTextColor(endColor); } }); } Loading @@ -239,6 +243,13 @@ public class TextChange extends Transition { Color.green(endColor) << 8 | Color.red(endColor)); } }); inAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { // restore opaque alpha and correct end color view.setTextColor(endColor); } }); } if (outAnim != null && inAnim != null) { anim = new AnimatorSet(); Loading @@ -251,23 +262,34 @@ public class TextChange extends Transition { } } TransitionListener transitionListener = new TransitionListenerAdapter() { boolean mCanceled = false; int mPausedColor = 0; @Override public void onTransitionPause(Transition transition) { if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(endText); if (view instanceof EditText) { setSelection(((EditText) view), endSelectionStart, endSelectionEnd); } } if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { mPausedColor = view.getCurrentTextColor(); view.setTextColor(endColor); } } @Override public void onTransitionResume(Transition transition) { if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(startText); if (view instanceof EditText) { setSelection(((EditText) view), startSelectionStart, startSelectionEnd); } } if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { view.setTextColor(mPausedColor); } } }; addListener(transitionListener); if (DBG) { Loading core/java/android/transition/Fade.java +41 −4 Original line number Diff line number Diff line Loading @@ -30,6 +30,24 @@ import android.view.ViewGroup; * {@link View#setVisibility(int)} state of the view as well as whether it * is parented in the current view hierarchy. * * <p>The ability of this transition to fade out a particular view, and the * way that that fading operation takes place, is based on * the situation of the view in the view hierarchy. For example, if a view was * simply removed from its parent, then the view will be added into a {@link * android.view.ViewGroupOverlay} while fading. If a visible view is * changed to be {@link View#GONE} or {@link View#INVISIBLE}, then the * visibility will be changed to {@link View#VISIBLE} for the duration of * the animation. However, if a view is in a hierarchy which is also altering * its visibility, the situation can be more complicated. In general, if a * view that is no longer in the hierarchy in the end scene still has a * parent (so its parent hierarchy was removed, but it was not removed from * its parent), then it will be left alone to avoid side-effects from * improperly removing it from its parent. The only exception to this is if * the previous {@link Scene} was * {@link Scene#getSceneForLayout(android.view.ViewGroup, int, android.content.Context) * created from a layout resource file}, then it is considered safe to un-parent * the starting scene view in order to fade it out.</p> * * <p>A Fade transition can be described in a resource file by using the * tag <code>fade</code>, along with the standard * attributes of {@link android.R.styleable#Fade} and Loading Loading @@ -167,7 +185,7 @@ public class Fade extends Visibility { if ((mFadingMode & OUT) != OUT) { return null; } View view; View view = null; View startView = (startValues != null) ? startValues.view : null; View endView = (endValues != null) ? endValues.view : null; if (DBG) { Loading @@ -177,9 +195,28 @@ public class Fade extends Visibility { View overlayView = null; View viewToKeep = null; if (endView == null || endView.getParent() == null) { // view was removed: add the start view to the Overlay view = startView; overlayView = view; if (endView != null) { // endView was removed from its parent - add it to the overlay view = overlayView = endView; } else if (startView != null) { // endView does not exist. Use startView only under certain // conditions, because placing a view in an overlay necessitates // it being removed from its current parent if (startView.getParent() == null) { // no parent - safe to use view = overlayView = startView; } else if (startView.getParent() instanceof View && startView.getParent().getParent() == null) { View startParent = (View) startView.getParent(); int id = startParent.getId(); if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) { // no parent, but its parent is unparented but the parent // hierarchy has been replaced by a new hierarchy with the same id // and it is safe to un-parent startView view = overlayView = startView; } } } } else { // visibility change if (endVisibility == View.INVISIBLE) { Loading core/java/android/transition/Scene.java +17 −2 Original line number Diff line number Diff line Loading @@ -157,11 +157,11 @@ public final class Scene { public void enter() { // Apply layout change, if any if (mLayoutId >= 0 || mLayout != null) { if (mLayoutId > 0 || mLayout != null) { // empty out parent container before adding to it getSceneRoot().removeAllViews(); if (mLayoutId >= 0) { if (mLayoutId > 0) { LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot); } else { mSceneRoot.addView(mLayout); Loading Loading @@ -242,4 +242,19 @@ public final class Scene { mExitAction = action; } /** * Returns whether this Scene was created by a layout resource file, determined * by the layoutId passed into * {@link #getSceneForLayout(android.view.ViewGroup, int, android.content.Context)}. * This is called by TransitionManager to determine whether it is safe for views from * this scene to be removed from their parents when the scene is exited, which is * used by {@link Fade} to fade these views out (the views must be removed from * their parent in order to add them to the overlay for fading purposes). If a * Scene is not based on a resource file, then the impact of removing views * arbitrarily is unknown and should be avoided. */ boolean isCreatedFromLayoutResource() { return (mLayoutId > 0); } } No newline at end of file core/java/android/transition/Transition.java +12 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,14 @@ public abstract class Transition implements Cloneable { // Scene Root is set at createAnimator() time in the cloned Transition ViewGroup mSceneRoot = null; // Whether removing views from their parent is possible. This is only for views // in the start scene, which are no longer in the view hierarchy. This property // is determined by whether the previous Scene was created from a layout // resource, and thus the views from the exited scene are going away anyway // and can be removed as necessary to achieve a particular effect, such as // removing them from parents to add them to overlays. boolean mCanRemoveViews = false; // Track all animators in use in case the transition gets canceled and needs to // cancel running animators private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>(); Loading Loading @@ -1445,6 +1453,10 @@ public abstract class Transition implements Cloneable { return this; } void setCanRemoveViews(boolean canRemoveViews) { mCanRemoveViews = canRemoveViews; } @Override public String toString() { return toString(""); Loading core/java/android/transition/TransitionManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -178,6 +178,11 @@ public class TransitionManager { Transition transitionClone = transition.clone(); transitionClone.setSceneRoot(sceneRoot); Scene oldScene = Scene.getCurrentScene(sceneRoot); if (oldScene != null && oldScene.isCreatedFromLayoutResource()) { transitionClone.setCanRemoveViews(true); } sceneChangeSetup(sceneRoot, transitionClone); scene.enter(); Loading Loading
core/java/android/transition/TextChange.java→core/java/android/transition/ChangeText.java +38 −16 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.Map; * * @hide */ public class TextChange extends Transition { public class ChangeText extends Transition { private static final String LOG_TAG = "TextChange"; Loading Loading @@ -103,7 +103,7 @@ public class TextChange extends Transition { * transition is run. * @return this textChange object. */ public TextChange setChangeBehavior(int changeBehavior) { public ChangeText setChangeBehavior(int changeBehavior) { if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) { mChangeBehavior = changeBehavior; } Loading Loading @@ -179,10 +179,14 @@ public class TextChange extends Transition { startSelectionStart = startSelectionEnd = endSelectionStart = endSelectionEnd = -1; } if (!startText.equals(endText)) { final int startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR); final int endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR); if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(startText); if (view instanceof EditText) { setSelection(((EditText) view), startSelectionStart, startSelectionEnd); } } Animator anim; if (mChangeBehavior == CHANGE_BEHAVIOR_KEEP) { anim = ValueAnimator.ofFloat(0, 1); Loading @@ -200,8 +204,6 @@ public class TextChange extends Transition { }); } else { // Fade out start text final int startColor = (Integer) startVals.get(PROPNAME_TEXT_COLOR); final int endColor = (Integer) endVals.get(PROPNAME_TEXT_COLOR); ValueAnimator outAnim = null, inAnim = null; if (mChangeBehavior == CHANGE_BEHAVIOR_OUT_IN || mChangeBehavior == CHANGE_BEHAVIOR_OUT) { Loading @@ -210,8 +212,8 @@ public class TextChange extends Transition { @Override public void onAnimationUpdate(ValueAnimator animation) { int currAlpha = (Integer) animation.getAnimatedValue(); view.setTextColor(currAlpha << 24 | Color.red(startColor) << 16 | Color.green(startColor) << 8 | Color.red(startColor)); view.setTextColor(currAlpha << 24 | startColor & 0xff0000 | startColor & 0xff00 | startColor & 0xff); } }); outAnim.addListener(new AnimatorListenerAdapter() { Loading @@ -225,6 +227,8 @@ public class TextChange extends Transition { endSelectionEnd); } } // restore opaque alpha and correct end color view.setTextColor(endColor); } }); } Loading @@ -239,6 +243,13 @@ public class TextChange extends Transition { Color.green(endColor) << 8 | Color.red(endColor)); } }); inAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { // restore opaque alpha and correct end color view.setTextColor(endColor); } }); } if (outAnim != null && inAnim != null) { anim = new AnimatorSet(); Loading @@ -251,23 +262,34 @@ public class TextChange extends Transition { } } TransitionListener transitionListener = new TransitionListenerAdapter() { boolean mCanceled = false; int mPausedColor = 0; @Override public void onTransitionPause(Transition transition) { if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(endText); if (view instanceof EditText) { setSelection(((EditText) view), endSelectionStart, endSelectionEnd); } } if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { mPausedColor = view.getCurrentTextColor(); view.setTextColor(endColor); } } @Override public void onTransitionResume(Transition transition) { if (mChangeBehavior != CHANGE_BEHAVIOR_IN) { view.setText(startText); if (view instanceof EditText) { setSelection(((EditText) view), startSelectionStart, startSelectionEnd); } } if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) { view.setTextColor(mPausedColor); } } }; addListener(transitionListener); if (DBG) { Loading
core/java/android/transition/Fade.java +41 −4 Original line number Diff line number Diff line Loading @@ -30,6 +30,24 @@ import android.view.ViewGroup; * {@link View#setVisibility(int)} state of the view as well as whether it * is parented in the current view hierarchy. * * <p>The ability of this transition to fade out a particular view, and the * way that that fading operation takes place, is based on * the situation of the view in the view hierarchy. For example, if a view was * simply removed from its parent, then the view will be added into a {@link * android.view.ViewGroupOverlay} while fading. If a visible view is * changed to be {@link View#GONE} or {@link View#INVISIBLE}, then the * visibility will be changed to {@link View#VISIBLE} for the duration of * the animation. However, if a view is in a hierarchy which is also altering * its visibility, the situation can be more complicated. In general, if a * view that is no longer in the hierarchy in the end scene still has a * parent (so its parent hierarchy was removed, but it was not removed from * its parent), then it will be left alone to avoid side-effects from * improperly removing it from its parent. The only exception to this is if * the previous {@link Scene} was * {@link Scene#getSceneForLayout(android.view.ViewGroup, int, android.content.Context) * created from a layout resource file}, then it is considered safe to un-parent * the starting scene view in order to fade it out.</p> * * <p>A Fade transition can be described in a resource file by using the * tag <code>fade</code>, along with the standard * attributes of {@link android.R.styleable#Fade} and Loading Loading @@ -167,7 +185,7 @@ public class Fade extends Visibility { if ((mFadingMode & OUT) != OUT) { return null; } View view; View view = null; View startView = (startValues != null) ? startValues.view : null; View endView = (endValues != null) ? endValues.view : null; if (DBG) { Loading @@ -177,9 +195,28 @@ public class Fade extends Visibility { View overlayView = null; View viewToKeep = null; if (endView == null || endView.getParent() == null) { // view was removed: add the start view to the Overlay view = startView; overlayView = view; if (endView != null) { // endView was removed from its parent - add it to the overlay view = overlayView = endView; } else if (startView != null) { // endView does not exist. Use startView only under certain // conditions, because placing a view in an overlay necessitates // it being removed from its current parent if (startView.getParent() == null) { // no parent - safe to use view = overlayView = startView; } else if (startView.getParent() instanceof View && startView.getParent().getParent() == null) { View startParent = (View) startView.getParent(); int id = startParent.getId(); if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) { // no parent, but its parent is unparented but the parent // hierarchy has been replaced by a new hierarchy with the same id // and it is safe to un-parent startView view = overlayView = startView; } } } } else { // visibility change if (endVisibility == View.INVISIBLE) { Loading
core/java/android/transition/Scene.java +17 −2 Original line number Diff line number Diff line Loading @@ -157,11 +157,11 @@ public final class Scene { public void enter() { // Apply layout change, if any if (mLayoutId >= 0 || mLayout != null) { if (mLayoutId > 0 || mLayout != null) { // empty out parent container before adding to it getSceneRoot().removeAllViews(); if (mLayoutId >= 0) { if (mLayoutId > 0) { LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot); } else { mSceneRoot.addView(mLayout); Loading Loading @@ -242,4 +242,19 @@ public final class Scene { mExitAction = action; } /** * Returns whether this Scene was created by a layout resource file, determined * by the layoutId passed into * {@link #getSceneForLayout(android.view.ViewGroup, int, android.content.Context)}. * This is called by TransitionManager to determine whether it is safe for views from * this scene to be removed from their parents when the scene is exited, which is * used by {@link Fade} to fade these views out (the views must be removed from * their parent in order to add them to the overlay for fading purposes). If a * Scene is not based on a resource file, then the impact of removing views * arbitrarily is unknown and should be avoided. */ boolean isCreatedFromLayoutResource() { return (mLayoutId > 0); } } No newline at end of file
core/java/android/transition/Transition.java +12 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,14 @@ public abstract class Transition implements Cloneable { // Scene Root is set at createAnimator() time in the cloned Transition ViewGroup mSceneRoot = null; // Whether removing views from their parent is possible. This is only for views // in the start scene, which are no longer in the view hierarchy. This property // is determined by whether the previous Scene was created from a layout // resource, and thus the views from the exited scene are going away anyway // and can be removed as necessary to achieve a particular effect, such as // removing them from parents to add them to overlays. boolean mCanRemoveViews = false; // Track all animators in use in case the transition gets canceled and needs to // cancel running animators private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>(); Loading Loading @@ -1445,6 +1453,10 @@ public abstract class Transition implements Cloneable { return this; } void setCanRemoveViews(boolean canRemoveViews) { mCanRemoveViews = canRemoveViews; } @Override public String toString() { return toString(""); Loading
core/java/android/transition/TransitionManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -178,6 +178,11 @@ public class TransitionManager { Transition transitionClone = transition.clone(); transitionClone.setSceneRoot(sceneRoot); Scene oldScene = Scene.getCurrentScene(sceneRoot); if (oldScene != null && oldScene.isCreatedFromLayoutResource()) { transitionClone.setCanRemoveViews(true); } sceneChangeSetup(sceneRoot, transitionClone); scene.enter(); Loading