am d1477e74
: Merge "Better Transition interruption" into klp-dev
* commit 'd1477e746065450b1900398e103f4715ccf81b35': Better Transition interruption
This commit is contained in:
@ -29496,19 +29496,18 @@ package android.view.transition {
|
||||
public abstract class Transition implements java.lang.Cloneable {
|
||||
ctor public Transition();
|
||||
method public void addListener(android.view.transition.Transition.TransitionListener);
|
||||
method protected void cancelTransition();
|
||||
method protected void cancel();
|
||||
method protected abstract void captureValues(android.view.transition.TransitionValues, boolean);
|
||||
method public android.view.transition.Transition clone();
|
||||
method public long getDuration();
|
||||
method public android.animation.TimeInterpolator getInterpolator();
|
||||
method public java.util.ArrayList<android.view.transition.Transition.TransitionListener> getListeners();
|
||||
method public java.lang.String getName();
|
||||
method public long getStartDelay();
|
||||
method public int[] getTargetIds();
|
||||
method public android.view.View[] getTargets();
|
||||
method public java.lang.String[] getTransitionProperties();
|
||||
method protected android.view.transition.TransitionValues getTransitionValues(android.view.View, boolean);
|
||||
method protected void onTransitionCancel();
|
||||
method protected void onTransitionEnd();
|
||||
method protected void onTransitionStart();
|
||||
method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
|
||||
method public void removeListener(android.view.transition.Transition.TransitionListener);
|
||||
method public android.view.transition.Transition setDuration(long);
|
||||
@ -29521,6 +29520,8 @@ package android.view.transition {
|
||||
public static abstract interface Transition.TransitionListener {
|
||||
method public abstract void onTransitionCancel(android.view.transition.Transition);
|
||||
method public abstract void onTransitionEnd(android.view.transition.Transition);
|
||||
method public abstract void onTransitionPause(android.view.transition.Transition);
|
||||
method public abstract void onTransitionResume(android.view.transition.Transition);
|
||||
method public abstract void onTransitionStart(android.view.transition.Transition);
|
||||
}
|
||||
|
||||
@ -29567,6 +29568,7 @@ package android.view.transition {
|
||||
method protected android.animation.Animator appear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
|
||||
method protected void captureValues(android.view.transition.TransitionValues, boolean);
|
||||
method protected android.animation.Animator disappear(android.view.ViewGroup, android.view.transition.TransitionValues, int, android.view.transition.TransitionValues, int);
|
||||
method public boolean isVisible(android.view.transition.TransitionValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5356,6 +5356,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether layout calls on this container are currently being
|
||||
* suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
|
||||
*
|
||||
* @return true if layout calls are currently suppressed, false otherwise.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isLayoutSuppressed() {
|
||||
return mSuppressLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@ package android.view.transition;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -35,6 +36,7 @@ public class Fade extends Visibility {
|
||||
private static boolean DBG = Transition.DBG && false;
|
||||
|
||||
private static final String LOG_TAG = "Fade";
|
||||
private static final String PROPNAME_ALPHA = "android:fade:alpha";
|
||||
private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
|
||||
private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
|
||||
|
||||
@ -74,26 +76,51 @@ public class Fade extends Visibility {
|
||||
/**
|
||||
* Utility method to handle creating and running the Animator.
|
||||
*/
|
||||
private Animator runAnimation(View view, float startAlpha, float endAlpha,
|
||||
Animator.AnimatorListener listener) {
|
||||
private Animator createAnimation(View view, float startAlpha, float endAlpha,
|
||||
AnimatorListenerAdapter listener) {
|
||||
if (startAlpha == endAlpha) {
|
||||
// run listener if we're noop'ing the animation, to get the end-state results now
|
||||
if (listener != null) {
|
||||
listener.onAnimationEnd(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
|
||||
if (listener != null) {
|
||||
anim.addListener(listener);
|
||||
anim.addPauseListener(listener);
|
||||
}
|
||||
// TODO: Maybe extract a method into Transition to run an animation that handles the
|
||||
// duration/startDelay stuff for all subclasses.
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureValues(TransitionValues values, boolean start) {
|
||||
super.captureValues(values, start);
|
||||
float alpha = values.view.getAlpha();
|
||||
values.values.put(PROPNAME_ALPHA, alpha);
|
||||
int[] loc = new int[2];
|
||||
values.view.getLocationOnScreen(loc);
|
||||
values.values.put(PROPNAME_SCREEN_X, loc[0]);
|
||||
values.values.put(PROPNAME_SCREEN_Y, loc[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
|
||||
TransitionValues endValues) {
|
||||
Animator animator = super.play(sceneRoot, startValues, endValues);
|
||||
if (animator == null && startValues != null && endValues != null) {
|
||||
boolean endVisible = isVisible(endValues);
|
||||
final View endView = endValues.view;
|
||||
float endAlpha = endView.getAlpha();
|
||||
float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
|
||||
if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
|
||||
(!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
|
||||
animator = createAnimation(endView, startAlpha, endAlpha, null);
|
||||
}
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator appear(ViewGroup sceneRoot,
|
||||
TransitionValues startValues, int startVisibility,
|
||||
@ -102,15 +129,11 @@ public class Fade extends Visibility {
|
||||
return null;
|
||||
}
|
||||
final View endView = endValues.view;
|
||||
endView.setAlpha(0);
|
||||
final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Always end animation with full alpha, in case it's canceled mid-stream
|
||||
endView.setAlpha(1);
|
||||
}
|
||||
};
|
||||
return runAnimation(endView, 0, 1, endListener);
|
||||
// if alpha < 1, just fade it in from the current value
|
||||
if (endView.getAlpha() == 1.0f) {
|
||||
endView.setAlpha(0);
|
||||
}
|
||||
return createAnimation(endView, endView.getAlpha(), 1, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,7 +152,7 @@ public class Fade extends Visibility {
|
||||
}
|
||||
View overlayView = null;
|
||||
View viewToKeep = null;
|
||||
if (endView == null) {
|
||||
if (endView == null || endView.getParent() == null) {
|
||||
// view was removed: add the start view to the Overlay
|
||||
view = startView;
|
||||
overlayView = view;
|
||||
@ -167,7 +190,7 @@ public class Fade extends Visibility {
|
||||
final View finalOverlayView = overlayView;
|
||||
final View finalViewToKeep = viewToKeep;
|
||||
final ViewGroup finalSceneRoot = sceneRoot;
|
||||
final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
|
||||
final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
finalView.setAlpha(startAlpha);
|
||||
@ -179,8 +202,22 @@ public class Fade extends Visibility {
|
||||
finalSceneRoot.getOverlay().remove(finalOverlayView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationPause(Animator animation) {
|
||||
if (finalOverlayView != null) {
|
||||
finalSceneRoot.getOverlay().remove(finalOverlayView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationResume(Animator animation) {
|
||||
if (finalOverlayView != null) {
|
||||
finalSceneRoot.getOverlay().add(finalOverlayView);
|
||||
}
|
||||
}
|
||||
};
|
||||
return runAnimation(view, startAlpha, endAlpha, endListener);
|
||||
return createAnimation(view, startAlpha, endAlpha, endListener);
|
||||
}
|
||||
if (viewToKeep != null) {
|
||||
// TODO: find a different way to do this, like just changing the view to be
|
||||
@ -193,12 +230,42 @@ public class Fade extends Visibility {
|
||||
final View finalOverlayView = overlayView;
|
||||
final View finalViewToKeep = viewToKeep;
|
||||
final ViewGroup finalSceneRoot = sceneRoot;
|
||||
final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
|
||||
final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
|
||||
boolean mCanceled = false;
|
||||
float mPausedAlpha = -1;
|
||||
|
||||
@Override
|
||||
public void onAnimationPause(Animator animation) {
|
||||
if (finalViewToKeep != null && !mCanceled) {
|
||||
finalViewToKeep.setVisibility(finalVisibility);
|
||||
}
|
||||
mPausedAlpha = finalView.getAlpha();
|
||||
finalView.setAlpha(startAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationResume(Animator animation) {
|
||||
if (finalViewToKeep != null && !mCanceled) {
|
||||
finalViewToKeep.setVisibility(View.VISIBLE);
|
||||
}
|
||||
finalView.setAlpha(mPausedAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCanceled = true;
|
||||
if (mPausedAlpha >= 0) {
|
||||
finalView.setAlpha(mPausedAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
finalView.setAlpha(startAlpha);
|
||||
if (!mCanceled) {
|
||||
finalView.setAlpha(startAlpha);
|
||||
}
|
||||
// TODO: restore view offset from overlay repositioning
|
||||
if (finalViewToKeep != null) {
|
||||
if (finalViewToKeep != null && !mCanceled) {
|
||||
finalViewToKeep.setVisibility(finalVisibility);
|
||||
}
|
||||
if (finalOverlayView != null) {
|
||||
@ -206,7 +273,7 @@ public class Fade extends Visibility {
|
||||
}
|
||||
}
|
||||
};
|
||||
return runAnimation(view, startAlpha, endAlpha, endListener);
|
||||
return createAnimation(view, startAlpha, endAlpha, endListener);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -25,8 +25,6 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@ -42,6 +40,13 @@ public class Move extends Transition {
|
||||
private static final String PROPNAME_PARENT = "android:move:parent";
|
||||
private static final String PROPNAME_WINDOW_X = "android:move:windowX";
|
||||
private static final String PROPNAME_WINDOW_Y = "android:move:windowY";
|
||||
private static String[] sTransitionProperties = {
|
||||
PROPNAME_BOUNDS,
|
||||
PROPNAME_PARENT,
|
||||
PROPNAME_WINDOW_X,
|
||||
PROPNAME_WINDOW_Y
|
||||
};
|
||||
|
||||
int[] tempLocation = new int[2];
|
||||
boolean mResizeClip = false;
|
||||
boolean mReparent = false;
|
||||
@ -49,6 +54,11 @@ public class Move extends Transition {
|
||||
|
||||
private static RectEvaluator sRectEvaluator = new RectEvaluator();
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
}
|
||||
|
||||
public void setResizeClip(boolean resizeClip) {
|
||||
mResizeClip = resizeClip;
|
||||
}
|
||||
@ -146,12 +156,33 @@ public class Move extends Transition {
|
||||
if (view.getParent() instanceof ViewGroup) {
|
||||
final ViewGroup parent = (ViewGroup) view.getParent();
|
||||
parent.suppressLayout(true);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
TransitionListener transitionListener = new TransitionListenerAdapter() {
|
||||
boolean mCanceled = false;
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
public void onTransitionCancel(Transition transition) {
|
||||
parent.suppressLayout(false);
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionEnd(Transition transition) {
|
||||
if (!mCanceled) {
|
||||
parent.suppressLayout(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionPause(Transition transition) {
|
||||
parent.suppressLayout(false);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onTransitionResume(Transition transition) {
|
||||
parent.suppressLayout(true);
|
||||
}
|
||||
};
|
||||
addListener(transitionListener);
|
||||
}
|
||||
return anim;
|
||||
} else {
|
||||
@ -191,12 +222,33 @@ public class Move extends Transition {
|
||||
if (view.getParent() instanceof ViewGroup) {
|
||||
final ViewGroup parent = (ViewGroup) view.getParent();
|
||||
parent.suppressLayout(true);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
TransitionListener transitionListener = new TransitionListenerAdapter() {
|
||||
boolean mCanceled = false;
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
public void onTransitionCancel(Transition transition) {
|
||||
parent.suppressLayout(false);
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionEnd(Transition transition) {
|
||||
if (!mCanceled) {
|
||||
parent.suppressLayout(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionPause(Transition transition) {
|
||||
parent.suppressLayout(false);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onTransitionResume(Transition transition) {
|
||||
parent.suppressLayout(true);
|
||||
}
|
||||
};
|
||||
addListener(transitionListener);
|
||||
}
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
|
@ -22,7 +22,6 @@ import android.animation.TimeInterpolator;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
@ -60,6 +59,8 @@ public abstract class Transition implements Cloneable {
|
||||
private static final String LOG_TAG = "Transition";
|
||||
static final boolean DBG = false;
|
||||
|
||||
private String mName = getClass().getName();
|
||||
|
||||
long mStartDelay = -1;
|
||||
long mDuration = -1;
|
||||
TimeInterpolator mInterpolator = null;
|
||||
@ -69,29 +70,29 @@ public abstract class Transition implements Cloneable {
|
||||
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
|
||||
TransitionGroup mParent = null;
|
||||
|
||||
// Per-animator information used for later canceling when future transitions overlap
|
||||
private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
|
||||
new ThreadLocal<ArrayMap<Animator, AnimationInfo>>();
|
||||
|
||||
// Scene Root is set at play() time in the cloned Transition
|
||||
ViewGroup mSceneRoot = null;
|
||||
|
||||
// Used to carry data between setup() and play(), cleared before every scene transition
|
||||
private ArrayList<TransitionValues> mPlayStartValuesList = new ArrayList<TransitionValues>();
|
||||
private ArrayList<TransitionValues> mPlayEndValuesList = new ArrayList<TransitionValues>();
|
||||
|
||||
// Track all animators in use in case the transition gets canceled and needs to
|
||||
// cancel running animators
|
||||
private ArrayList<Animator> mCurrentAnimators = new ArrayList<Animator>();
|
||||
|
||||
// Number of per-target instances of this Transition currently running. This count is
|
||||
// determined by calls to startTransition() and endTransition()
|
||||
// determined by calls to start() and end()
|
||||
int mNumInstances = 0;
|
||||
|
||||
|
||||
// Whether this transition is currently paused, due to a call to pause()
|
||||
boolean mPaused = false;
|
||||
|
||||
// The set of listeners to be sent transition lifecycle events.
|
||||
ArrayList<TransitionListener> mListeners = null;
|
||||
|
||||
// The set of animators collected from calls to play(), to be run in runAnimations()
|
||||
ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap =
|
||||
new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>();
|
||||
ArrayList<Animator> mAnimators = new ArrayList<Animator>();
|
||||
|
||||
/**
|
||||
* Constructs a Transition object with no target objects. A transition with
|
||||
@ -115,6 +116,14 @@ public abstract class Transition implements Cloneable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration set on this transition. If no duration has been set,
|
||||
* the returned value will be negative, indicating that resulting animators will
|
||||
* retain their own durations.
|
||||
*
|
||||
* @return The duration set on this transition, if one has been set, otherwise
|
||||
* returns a negative number.
|
||||
*/
|
||||
public long getDuration() {
|
||||
return mDuration;
|
||||
}
|
||||
@ -131,6 +140,14 @@ public abstract class Transition implements Cloneable {
|
||||
mStartDelay = startDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the startDelay set on this transition. If no startDelay has been set,
|
||||
* the returned value will be negative, indicating that resulting animators will
|
||||
* retain their own startDelays.
|
||||
*
|
||||
* @return The startDealy set on this transition, if one has been set, otherwise
|
||||
* returns a negative number.
|
||||
*/
|
||||
public long getStartDelay() {
|
||||
return mStartDelay;
|
||||
}
|
||||
@ -147,10 +164,43 @@ public abstract class Transition implements Cloneable {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolator set on this transition. If no interpolator has been set,
|
||||
* the returned value will be null, indicating that resulting animators will
|
||||
* retain their own interpolators.
|
||||
*
|
||||
* @return The interpolator set on this transition, if one has been set, otherwise
|
||||
* returns null.
|
||||
*/
|
||||
public TimeInterpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of property names used stored in the {@link TransitionValues}
|
||||
* object passed into {@link #captureValues(TransitionValues, boolean)} that
|
||||
* this transition cares about for the purposes of canceling overlapping animations.
|
||||
* When any transition is started on a given scene root, all transitions
|
||||
* currently running on that same scene root are checked to see whether the
|
||||
* properties on which they based their animations agree with the end values of
|
||||
* the same properties in the new transition. If the end values are not equal,
|
||||
* then the old animation is canceled since the new transition will start a new
|
||||
* animation to these new values. If the values are equal, the old animation is
|
||||
* allowed to continue and no new animation is started for that transition.
|
||||
*
|
||||
* <p>A transition does not need to override this method. However, not doing so
|
||||
* will mean that the cancellation logic outlined in the previous paragraph
|
||||
* will be skipped for that transition, possibly leading to artifacts as
|
||||
* old transitions and new transitions on the same targets run in parallel,
|
||||
* animating views toward potentially different end values.</p>
|
||||
*
|
||||
* @return An array of property names as described in the class documentation for
|
||||
* {@link TransitionValues}. The default implementation returns <code>null</code>.
|
||||
*/
|
||||
public String[] getTransitionProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the transition's parent (all the way up to the
|
||||
* topmost Transition in the hierarchy) with the sceneRoot and start/end
|
||||
@ -210,8 +260,6 @@ public abstract class Transition implements Cloneable {
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "play() for " + this);
|
||||
}
|
||||
mPlayStartValuesList.clear();
|
||||
mPlayEndValuesList.clear();
|
||||
ArrayMap<View, TransitionValues> endCopy =
|
||||
new ArrayMap<View, TransitionValues>(endValues.viewValues);
|
||||
SparseArray<TransitionValues> endIdCopy =
|
||||
@ -316,6 +364,7 @@ public abstract class Transition implements Cloneable {
|
||||
startValuesList.add(start);
|
||||
endValuesList.add(end);
|
||||
}
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
|
||||
for (int i = 0; i < startValuesList.size(); ++i) {
|
||||
TransitionValues start = startValuesList.get(i);
|
||||
TransitionValues end = endValuesList.get(i);
|
||||
@ -345,14 +394,46 @@ public abstract class Transition implements Cloneable {
|
||||
// TODO: what to do about targetIds and itemIds?
|
||||
Animator animator = play(sceneRoot, start, end);
|
||||
if (animator != null) {
|
||||
mAnimatorMap.put(new Pair(start, end), animator);
|
||||
// Note: we've already done the check against targetIDs in these lists
|
||||
mPlayStartValuesList.add(start);
|
||||
mPlayEndValuesList.add(end);
|
||||
// Save animation info for future cancellation purposes
|
||||
View view = null;
|
||||
TransitionValues infoValues = null;
|
||||
if (end != null) {
|
||||
view = end.view;
|
||||
String[] properties = getTransitionProperties();
|
||||
if (view != null && properties != null && properties.length > 0) {
|
||||
infoValues = new TransitionValues();
|
||||
infoValues.view = view;
|
||||
TransitionValues newValues = endValues.viewValues.get(view);
|
||||
if (newValues != null) {
|
||||
for (int j = 0; j < properties.length; ++j) {
|
||||
infoValues.values.put(properties[j],
|
||||
newValues.values.get(properties[j]));
|
||||
}
|
||||
}
|
||||
int numExistingAnims = runningAnimators.size();
|
||||
for (int j = 0; j < numExistingAnims; ++j) {
|
||||
Animator anim = runningAnimators.keyAt(j);
|
||||
AnimationInfo info = runningAnimators.get(anim);
|
||||
if (info.values != null && info.view == view &&
|
||||
((info.name == null && getName() == null) ||
|
||||
info.name.equals(getName()))) {
|
||||
if (info.values.equals(infoValues)) {
|
||||
// Favor the old animator
|
||||
animator = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
view = (start != null) ? start.view : null;
|
||||
}
|
||||
if (animator != null) {
|
||||
AnimationInfo info = new AnimationInfo(view, getName(), infoValues);
|
||||
runningAnimators.put(animator, info);
|
||||
mAnimators.add(animator);
|
||||
}
|
||||
}
|
||||
} else if (DBG) {
|
||||
View view = (end != null) ? end.view : start.view;
|
||||
Log.d(LOG_TAG, " No change for view " + view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -389,6 +470,15 @@ public abstract class Transition implements Cloneable {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
|
||||
if (runningAnimators == null) {
|
||||
runningAnimators = new ArrayMap<Animator, AnimationInfo>();
|
||||
sRunningAnimators.set(runningAnimators);
|
||||
}
|
||||
return runningAnimators;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called internally once all animations have been set up by the
|
||||
* transition hierarchy. \
|
||||
@ -396,28 +486,27 @@ public abstract class Transition implements Cloneable {
|
||||
* @hide
|
||||
*/
|
||||
protected void runAnimations() {
|
||||
if (DBG && mPlayStartValuesList.size() > 0) {
|
||||
Log.d(LOG_TAG, "runAnimations (" + mPlayStartValuesList.size() + ") on " + this);
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "runAnimations() on " + this);
|
||||
}
|
||||
startTransition();
|
||||
// Now walk the list of TransitionValues, calling play for each pair
|
||||
for (int i = 0; i < mPlayStartValuesList.size(); ++i) {
|
||||
TransitionValues start = mPlayStartValuesList.get(i);
|
||||
TransitionValues end = mPlayEndValuesList.get(i);
|
||||
Animator anim = mAnimatorMap.get(new Pair(start, end));
|
||||
start();
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
|
||||
// Now start every Animator that was previously created for this transition in play()
|
||||
for (Animator anim : mAnimators) {
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, " anim: " + anim);
|
||||
}
|
||||
startTransition();
|
||||
runAnimator(anim);
|
||||
if (runningAnimators.containsKey(anim)) {
|
||||
start();
|
||||
runAnimator(anim, runningAnimators);
|
||||
}
|
||||
}
|
||||
mPlayStartValuesList.clear();
|
||||
mPlayEndValuesList.clear();
|
||||
mAnimatorMap.clear();
|
||||
endTransition();
|
||||
mAnimators.clear();
|
||||
end();
|
||||
}
|
||||
|
||||
private void runAnimator(Animator animator) {
|
||||
private void runAnimator(Animator animator,
|
||||
final ArrayMap<Animator, AnimationInfo> runningAnimators) {
|
||||
if (animator != null) {
|
||||
// TODO: could be a single listener instance for all of them since it uses the param
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@ -427,6 +516,7 @@ public abstract class Transition implements Cloneable {
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
runningAnimators.remove(animation);
|
||||
mCurrentAnimators.remove(animation);
|
||||
}
|
||||
});
|
||||
@ -690,12 +780,113 @@ public abstract class Transition implements Cloneable {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses this transition, sending out calls to {@link
|
||||
* TransitionListener#onTransitionPause(Transition)} to all listeners
|
||||
* and pausing all running animators started by this transition.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void pause() {
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
|
||||
int numOldAnims = runningAnimators.size();
|
||||
for (int i = numOldAnims - 1; i >= 0; i--) {
|
||||
Animator anim = runningAnimators.keyAt(i);
|
||||
anim.pause();
|
||||
}
|
||||
if (mListeners != null && mListeners.size() > 0) {
|
||||
ArrayList<TransitionListener> tmpListeners =
|
||||
(ArrayList<TransitionListener>) mListeners.clone();
|
||||
int numListeners = tmpListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
tmpListeners.get(i).onTransitionPause(this);
|
||||
}
|
||||
}
|
||||
mPaused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes this transition, sending out calls to {@link
|
||||
* TransitionListener#onTransitionPause(Transition)} to all listeners
|
||||
* and pausing all running animators started by this transition.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void resume() {
|
||||
if (mPaused) {
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
|
||||
int numOldAnims = runningAnimators.size();
|
||||
for (int i = numOldAnims - 1; i >= 0; i--) {
|
||||
Animator anim = runningAnimators.keyAt(i);
|
||||
anim.resume();
|
||||
}
|
||||
if (mListeners != null && mListeners.size() > 0) {
|
||||
ArrayList<TransitionListener> tmpListeners =
|
||||
(ArrayList<TransitionListener>) mListeners.clone();
|
||||
int numListeners = tmpListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
tmpListeners.get(i).onTransitionResume(this);
|
||||
}
|
||||
}
|
||||
mPaused = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by TransitionManager to play the transition. This calls
|
||||
* play() to set things up and create all of the animations and then
|
||||
* runAnimations() to actually start the animations.
|
||||
*/
|
||||
void playTransition(ViewGroup sceneRoot) {
|
||||
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
|
||||
int numOldAnims = runningAnimators.size();
|
||||
for (int i = numOldAnims - 1; i >= 0; i--) {
|
||||
Animator anim = runningAnimators.keyAt(i);
|
||||
if (anim != null) {
|
||||
anim.resume();
|
||||
AnimationInfo oldInfo = runningAnimators.get(anim);
|
||||
if (oldInfo != null) {
|
||||
boolean cancel = false;
|
||||
TransitionValues oldValues = oldInfo.values;
|
||||
View oldView = oldInfo.view;
|
||||
TransitionValues newValues = mEndValues.viewValues != null ?
|
||||
mEndValues.viewValues.get(oldView) : null;
|
||||
if (oldValues == null || newValues == null) {
|
||||
if (oldValues != null || newValues != null) {
|
||||
cancel = true;
|
||||
}
|
||||
} else {
|
||||
for (String key : oldValues.values.keySet()) {
|
||||
Object oldValue = oldValues.values.get(key);
|
||||
Object newValue = newValues.values.get(key);
|
||||
if ((oldValue == null && newValue != null) ||
|
||||
(oldValue != null && !oldValue.equals(newValue))) {
|
||||
cancel = true;
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "Transition.play: oldValue != newValue for " +
|
||||
key + ": old, new = " + oldValue + ", " + newValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cancel) {
|
||||
if (anim.isRunning() || anim.isStarted()) {
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "Canceling anim " + anim);
|
||||
}
|
||||
anim.cancel();
|
||||
} else {
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "removing anim from info list: " + anim);
|
||||
}
|
||||
runningAnimators.remove(anim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup() must be called on entire transition hierarchy and set of views
|
||||
// before calling play() on anything; every transition needs a chance to set up
|
||||
// target views appropriately before transitions begin running
|
||||
@ -707,7 +898,7 @@ public abstract class Transition implements Cloneable {
|
||||
* This is a utility method used by subclasses to handle standard parts of
|
||||
* setting up and running an Animator: it sets the {@link #getDuration()
|
||||
* duration} and the {@link #getStartDelay() startDelay}, starts the
|
||||
* animation, and, when the animator ends, calls {@link #endTransition()}.
|
||||
* animation, and, when the animator ends, calls {@link #end()}.
|
||||
*
|
||||
* @param animator The Animator to be run during this transition.
|
||||
*
|
||||
@ -716,7 +907,7 @@ public abstract class Transition implements Cloneable {
|
||||
protected void animate(Animator animator) {
|
||||
// TODO: maybe pass auto-end as a boolean parameter?
|
||||
if (animator == null) {
|
||||
endTransition();
|
||||
end();
|
||||
} else {
|
||||
if (getDuration() >= 0) {
|
||||
animator.setDuration(getDuration());
|
||||
@ -730,7 +921,7 @@ public abstract class Transition implements Cloneable {
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
endTransition();
|
||||
end();
|
||||
animation.removeListener(this);
|
||||
}
|
||||
});
|
||||
@ -738,30 +929,6 @@ public abstract class Transition implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override to receive notice of when the transition starts.
|
||||
* This is equivalent to listening for the
|
||||
* {@link TransitionListener#onTransitionStart(Transition)} callback.
|
||||
*/
|
||||
protected void onTransitionStart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override to receive notice of when the transition is
|
||||
* canceled. This is equivalent to listening for the
|
||||
* {@link TransitionListener#onTransitionCancel(Transition)} callback.
|
||||
*/
|
||||
protected void onTransitionCancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override to receive notice of when the transition ends.
|
||||
* This is equivalent to listening for the
|
||||
* {@link TransitionListener#onTransitionEnd(Transition)} callback.
|
||||
*/
|
||||
protected void onTransitionEnd() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called automatically by the transition and
|
||||
* TransitionGroup classes prior to a Transition subclass starting;
|
||||
@ -769,9 +936,8 @@ public abstract class Transition implements Cloneable {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
protected void startTransition() {
|
||||
protected void start() {
|
||||
if (mNumInstances == 0) {
|
||||
onTransitionStart();
|
||||
if (mListeners != null && mListeners.size() > 0) {
|
||||
ArrayList<TransitionListener> tmpListeners =
|
||||
(ArrayList<TransitionListener>) mListeners.clone();
|
||||
@ -790,15 +956,14 @@ public abstract class Transition implements Cloneable {
|
||||
* a transition did nothing (returned a null Animator from
|
||||
* {@link Transition#play(ViewGroup, TransitionValues,
|
||||
* TransitionValues)}) or because the transition returned a valid
|
||||
* Animator and endTransition() was called in the onAnimationEnd()
|
||||
* Animator and end() was called in the onAnimationEnd()
|
||||
* callback of the AnimatorListener.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
protected void endTransition() {
|
||||
protected void end() {
|
||||
--mNumInstances;
|
||||
if (mNumInstances == 0) {
|
||||
onTransitionEnd();
|
||||
if (mListeners != null && mListeners.size() > 0) {
|
||||
ArrayList<TransitionListener> tmpListeners =
|
||||
(ArrayList<TransitionListener>) mListeners.clone();
|
||||
@ -828,7 +993,7 @@ public abstract class Transition implements Cloneable {
|
||||
* This method cancels a transition that is currently running.
|
||||
* Implementation TBD.
|
||||
*/
|
||||
protected void cancelTransition() {
|
||||
protected void cancel() {
|
||||
// TODO: how does this work with instances?
|
||||
// TODO: this doesn't actually do *anything* yet
|
||||
int numAnimators = mCurrentAnimators.size();
|
||||
@ -836,7 +1001,6 @@ public abstract class Transition implements Cloneable {
|
||||
Animator animator = mCurrentAnimators.get(i);
|
||||
animator.cancel();
|
||||
}
|
||||
onTransitionCancel();
|
||||
if (mListeners != null && mListeners.size() > 0) {
|
||||
ArrayList<TransitionListener> tmpListeners =
|
||||
(ArrayList<TransitionListener>) mListeners.clone();
|
||||
@ -901,11 +1065,28 @@ public abstract class Transition implements Cloneable {
|
||||
Transition clone = null;
|
||||
try {
|
||||
clone = (Transition) super.clone();
|
||||
clone.mAnimators = new ArrayList<Animator>();
|
||||
} catch (CloneNotSupportedException e) {}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this Transition. This name is used internally to distinguish
|
||||
* between different transitions to determine when interrupting transitions overlap.
|
||||
* For example, a Move running on the same target view as another Move should determine
|
||||
* whether the old transition is animating to different end values and should be
|
||||
* canceled in favor of the new transition.
|
||||
*
|
||||
* <p>By default, a Transition's name is simply the value of {@link Class#getName()},
|
||||
* but subclasses are free to override and return something different.</p>
|
||||
*
|
||||
* @return The name of this transition.
|
||||
*/
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
String toString(String indent) {
|
||||
String result = indent + getClass().getSimpleName() + "@" +
|
||||
Integer.toHexString(hashCode()) + ": ";
|
||||
@ -943,8 +1124,7 @@ public abstract class Transition implements Cloneable {
|
||||
|
||||
/**
|
||||
* A transition listener receives notifications from a transition.
|
||||
* Notifications indicate transition lifecycle events: when the transition
|
||||
* begins, ends, or is canceled.
|
||||
* Notifications indicate transition lifecycle events.
|
||||
*/
|
||||
public static interface TransitionListener {
|
||||
/**
|
||||
@ -957,7 +1137,7 @@ public abstract class Transition implements Cloneable {
|
||||
/**
|
||||
* Notification about the end of the transition. Canceled transitions
|
||||
* will always notify listeners of both the cancellation and end
|
||||
* events. That is, {@link #onTransitionEnd()} is always called,
|
||||
* events. That is, {@link #onTransitionEnd(Transition)} is always called,
|
||||
* regardless of whether the transition was canceled or played
|
||||
* through to completion.
|
||||
*
|
||||
@ -967,10 +1147,38 @@ public abstract class Transition implements Cloneable {
|
||||
|
||||
/**
|
||||
* Notification about the cancellation of the transition.
|
||||
* Note that cancel() may be called by a parent {@link TransitionGroup} on
|
||||
* a child transition which has not yet started. This allows the child
|
||||
* transition to restore state on target objects which was set at
|
||||
* {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
|
||||
* play()} time.
|
||||
*
|
||||
* @param transition The transition which was canceled.
|
||||
*/
|
||||
void onTransitionCancel(Transition transition);
|
||||
|
||||
/**
|
||||
* Notification when a transition is paused.
|
||||
* Note that play() may be called by a parent {@link TransitionGroup} on
|
||||
* a child transition which has not yet started. This allows the child
|
||||
* transition to restore state on target objects which was set at
|
||||
* {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
|
||||
* play()} time.
|
||||
*
|
||||
* @param transition The transition which was paused.
|
||||
*/
|
||||
void onTransitionPause(Transition transition);
|
||||
|
||||
/**
|
||||
* Notification when a transition is resumed.
|
||||
* Note that resume() may be called by a parent {@link TransitionGroup} on
|
||||
* a child transition which has not yet started. This allows the child
|
||||
* transition to restore state which may have changed in an earlier call
|
||||
* to {@link #onTransitionPause(Transition)}.
|
||||
*
|
||||
* @param transition The transition which was resumed.
|
||||
*/
|
||||
void onTransitionResume(Transition transition);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -991,6 +1199,32 @@ public abstract class Transition implements Cloneable {
|
||||
@Override
|
||||
public void onTransitionCancel(Transition transition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionPause(Transition transition) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransitionResume(Transition transition) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds information about each animator used when a new transition starts
|
||||
* while other transitions are still running to determine whether a running
|
||||
* animation should be canceled or a new animation noop'd. The structure holds
|
||||
* information about the state that an animation is going to, to be compared to
|
||||
* end state of a new animation.
|
||||
*/
|
||||
private static class AnimationInfo {
|
||||
View view;
|
||||
String name;
|
||||
TransitionValues values;
|
||||
|
||||
AnimationInfo(View view, String name, TransitionValues values) {
|
||||
this.view = view;
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class TransitionGroup extends Transition {
|
||||
@Override
|
||||
public void onTransitionStart(Transition transition) {
|
||||
if (!mTransitionGroup.mStarted) {
|
||||
mTransitionGroup.startTransition();
|
||||
mTransitionGroup.start();
|
||||
mTransitionGroup.mStarted = true;
|
||||
}
|
||||
}
|
||||
@ -175,7 +175,7 @@ public class TransitionGroup extends Transition {
|
||||
if (mTransitionGroup.mCurrentListeners == 0) {
|
||||
// All child trans
|
||||
mTransitionGroup.mStarted = false;
|
||||
mTransitionGroup.endTransition();
|
||||
mTransitionGroup.end();
|
||||
}
|
||||
transition.removeListener(this);
|
||||
}
|
||||
@ -233,12 +233,32 @@ public class TransitionGroup extends Transition {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected void cancelTransition() {
|
||||
super.cancelTransition();
|
||||
public void pause() {
|
||||
super.pause();
|
||||
int numTransitions = mTransitions.size();
|
||||
for (int i = 0; i < numTransitions; ++i) {
|
||||
mTransitions.get(i).cancelTransition();
|
||||
mTransitions.get(i).pause();
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void resume() {
|
||||
super.resume();
|
||||
int numTransitions = mTransitions.size();
|
||||
for (int i = 0; i < numTransitions; ++i) {
|
||||
mTransitions.get(i).resume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancel() {
|
||||
super.cancel();
|
||||
int numTransitions = mTransitions.size();
|
||||
for (int i = 0; i < numTransitions; ++i) {
|
||||
mTransitions.get(i).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package android.view.transition;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
@ -45,8 +46,8 @@ public class TransitionManager {
|
||||
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
|
||||
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
|
||||
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
|
||||
static ArrayMap<ViewGroup, Transition> sRunningTransitions =
|
||||
new ArrayMap<ViewGroup, Transition>();
|
||||
private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
|
||||
new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
|
||||
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
|
||||
|
||||
|
||||
@ -160,6 +161,16 @@ public class TransitionManager {
|
||||
sceneChangeRunTransition(sceneRoot, transitionClone);
|
||||
}
|
||||
|
||||
private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
|
||||
ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
|
||||
sRunningTransitions.get();
|
||||
if (runningTransitions == null) {
|
||||
runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
|
||||
sRunningTransitions.set(runningTransitions);
|
||||
}
|
||||
return runningTransitions;
|
||||
}
|
||||
|
||||
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
|
||||
final Transition transition) {
|
||||
if (transition != null) {
|
||||
@ -169,16 +180,31 @@ public class TransitionManager {
|
||||
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
sPendingTransitions.remove(sceneRoot);
|
||||
// Add to running list, handle end to remove it
|
||||
sRunningTransitions.put(sceneRoot, transition);
|
||||
final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
|
||||
getRunningTransitions();
|
||||
ArrayList<Transition> currentTransitions = runningTransitions.get(sceneRoot);
|
||||
if (currentTransitions == null) {
|
||||
currentTransitions = new ArrayList<Transition>();
|
||||
runningTransitions.put(sceneRoot, currentTransitions);
|
||||
}
|
||||
currentTransitions.add(transition);
|
||||
transition.addListener(new Transition.TransitionListenerAdapter() {
|
||||
@Override
|
||||
public void onTransitionEnd(Transition transition) {
|
||||
sRunningTransitions.remove(sceneRoot);
|
||||
ArrayList<Transition> currentTransitions =
|
||||
runningTransitions.get(sceneRoot);
|
||||
currentTransitions.remove(transition);
|
||||
}
|
||||
});
|
||||
transition.captureValues(sceneRoot, false);
|
||||
transition.playTransition(sceneRoot);
|
||||
return true;
|
||||
|
||||
// Returning false from onPreDraw() skips the current frame. This is
|
||||
// necessary to avoid artifacts caused by resetting target views
|
||||
// to their proper end states for capturing. Waiting until the next
|
||||
// frame to draw allows these views to have their mid-transition
|
||||
// values set on them again and avoid artifacts.
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -187,16 +213,18 @@ public class TransitionManager {
|
||||
private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
|
||||
|
||||
// Capture current values
|
||||
Transition runningTransition = sRunningTransitions.get(sceneRoot);
|
||||
ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
|
||||
|
||||
if (runningTransitions != null && runningTransitions.size() > 0) {
|
||||
for (Transition runningTransition : runningTransitions) {
|
||||
runningTransition.pause();
|
||||
}
|
||||
}
|
||||
|
||||
if (transition != null) {
|
||||
transition.captureValues(sceneRoot, true);
|
||||
}
|
||||
|
||||
if (runningTransition != null) {
|
||||
runningTransition.cancelTransition();
|
||||
}
|
||||
|
||||
// Notify previous scene that it is being exited
|
||||
Scene previousScene = sceneRoot.getCurrentScene();
|
||||
if (previousScene != null) {
|
||||
|
@ -19,6 +19,7 @@ package android.view.transition;
|
||||
import android.animation.Animator;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOverlay;
|
||||
import android.view.ViewParent;
|
||||
|
||||
/**
|
||||
@ -38,6 +39,10 @@ public abstract class Visibility extends Transition {
|
||||
|
||||
private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
|
||||
private static final String PROPNAME_PARENT = "android:visibility:parent";
|
||||
private static String[] sTransitionProperties = {
|
||||
PROPNAME_VISIBILITY,
|
||||
PROPNAME_PARENT,
|
||||
};
|
||||
|
||||
private static class VisibilityInfo {
|
||||
boolean visibilityChange;
|
||||
@ -51,6 +56,11 @@ public abstract class Visibility extends Transition {
|
||||
// Temporary structure, used in calculating state in setup() and play()
|
||||
private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureValues(TransitionValues values, boolean start) {
|
||||
int visibility = values.view.getVisibility();
|
||||
@ -58,6 +68,31 @@ public abstract class Visibility extends Transition {
|
||||
values.values.put(PROPNAME_PARENT, values.view.getParent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the view is 'visible' according to the given values
|
||||
* object. This is determined by testing the same properties in the values
|
||||
* object that are used to determine whether the object is appearing or
|
||||
* disappearing in the {@link
|
||||
* #play(android.view.ViewGroup, TransitionValues, TransitionValues)}
|
||||
* method. This method can be called by, for example, subclasses that want
|
||||
* to know whether the object is visible in the same way that Visibility
|
||||
* determines it for the actual animation.
|
||||
*
|
||||
* @param values The TransitionValues object that holds the information by
|
||||
* which visibility is determined.
|
||||
* @return True if the view reference by <code>values</code> is visible,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean isVisible(TransitionValues values) {
|
||||
if (values == null) {
|
||||
return false;
|
||||
}
|
||||
int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
|
||||
View parent = (View) values.values.get(PROPNAME_PARENT);
|
||||
|
||||
return visibility == View.VISIBLE && parent != null;
|
||||
}
|
||||
|
||||
private boolean isHierarchyVisibilityChanging(ViewGroup sceneRoot, ViewGroup view) {
|
||||
|
||||
if (view == sceneRoot) {
|
||||
@ -197,5 +232,4 @@ public abstract class Visibility extends Transition {
|
||||
TransitionValues endValues, int endVisibility) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user