/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.transition; import android.animation.Animator; import android.animation.TimeInterpolator; import android.os.Build; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.SurfaceView; import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.widget.Spinner; import java.util.List; /** * A Transition holds information about animations that will be run on its * targets during a scene change. Subclasses of this abstract class may * choreograph several child transitions ({@link TransitionSet} or they may * perform custom animations themselves. Any Transition has two main jobs: * (1) capture property values, and (2) play animations based on changes to * captured property values. A custom transition knows what property values * on View objects are of interest to it, and also knows how to animate * changes to those values. For example, the {@link Fade} transition tracks * changes to visibility-related properties and is able to construct and run * animations that fade items in or out based on changes to those properties. * *
Note: Transitions may not work correctly with either {@link SurfaceView} * or {@link TextureView}, due to the way that these views are displayed * on the screen. For SurfaceView, the problem is that the view is updated from * a non-UI thread, so changes to the view due to transitions (such as moving * and resizing the view) may be out of sync with the display inside those bounds. * TextureView is more compatible with transitions in general, but some * specific transitions (such as {@link Fade}) may not be compatible * with TextureView because they rely on {@link android.view.ViewOverlay} * functionality, which does not currently work with TextureView.
* *Unlike the platform version, this does not support declaration by XML resources.
*/ public abstract class Transition implements TransitionInterface { /* package */ TransitionImpl mImpl; /** * Constructs a Transition object with no target objects. A transition with * no targets defaults to running on all target objects in the scene hierarchy * (if the transition is not contained in a TransitionSet), or all target * objects passed down from its parent (if it is in a TransitionSet). */ public Transition() { this(false); } // Hidden constructor for built-in transitions Transition(boolean deferred) { if (!deferred) { if (Build.VERSION.SDK_INT >= 23) { mImpl = new TransitionApi23(); } else if (Build.VERSION.SDK_INT >= 19) { mImpl = new TransitionKitKat(); } else { mImpl = new TransitionIcs(); } mImpl.init(this); } } /** * Adds a listener to the set of listeners that are sent events through the * life of an animation, such as start, repeat, and end. * * @param listener the listener to be added to the current set of listeners * for this animation. * @return This transition object. */ @NonNull public Transition addListener(@NonNull TransitionListener listener) { mImpl.addListener(listener); return this; } /** * Sets the target view instances that this Transition is interested in * animating. By default, there are no targets, and a Transition will * listen for changes on every view in the hierarchy below the sceneRoot * of the Scene being transitioned into. Setting targets constrains * the Transition to only listen for, and act on, these views. * All other views will be ignored. * *The target list is like the {@link #addTarget(int) targetId} * list except this list specifies the actual View instances, not the ids * of the views. This is an important distinction when scene changes involve * view hierarchies which have been inflated separately; different views may * share the same id but not actually be the same instance. If the transition * should treat those views as the same, then {@link #addTarget(int)} should be used * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve * changes all within the same view hierarchy, among views which do not * necessarily have ids set on them, then the target list of views may be more * convenient.
* * @param target A View on which the Transition will act, must be non-null. * @return The Transition to which the target is added. * Returning the same object makes it easier to chain calls during * construction, such as *transitionSet.addTransitions(new Fade()).addTarget(someView);
* @see #addTarget(int)
*/
@NonNull
public Transition addTarget(@NonNull View target) {
mImpl.addTarget(target);
return this;
}
/**
* Adds the id of a target view that this Transition is interested in
* animating. By default, there are no targetIds, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
* of the Scene being transitioned into. Setting targetIds constrains
* the Transition to only listen for, and act on, views with these IDs.
* Views with different IDs, or no IDs whatsoever, will be ignored.
*
* Note that using ids to specify targets implies that ids should be unique * within the view hierarchy underneath the scene root.
* * @param targetId The id of a target view, must be a positive number. * @return The Transition to which the targetId is added. * Returning the same object makes it easier to chain calls during * construction, such as *transitionSet.addTransitions(new Fade()).addTarget(someId);
* @see View#getId()
*/
@NonNull
public Transition addTarget(@IdRes int targetId) {
mImpl.addTarget(targetId);
return this;
}
/**
* Captures the values in the end scene for the properties that this
* transition monitors. These values are then passed as the endValues
* structure in a later call to
* {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
* The main concern for an implementation is what the
* properties are that the transition cares about and what the values are
* for all of those properties. The start and end values will be compared
* later during the
* {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
* method to determine what, if any, animations, should be run.
*
* Subclasses must implement this method. The method should only be called by the * transition system; it is not intended to be called from external classes.
* * @param transitionValues The holder for any values that the Transition * wishes to store. Values are stored in thevalues
field
* of this TransitionValues object and are keyed from
* a String value. For example, to store a view's rotation value,
* a transition might call
* transitionValues.values.put("appname:transitionname:rotation",
* view.getRotation())
. The target view will already be stored
* in
* the transitionValues structure when this method is called.
* @see #captureStartValues(TransitionValues)
* @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
*/
@Override
public abstract void captureEndValues(@NonNull TransitionValues transitionValues);
/**
* Captures the values in the start scene for the properties that this
* transition monitors. These values are then passed as the startValues
* structure in a later call to
* {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
* The main concern for an implementation is what the
* properties are that the transition cares about and what the values are
* for all of those properties. The start and end values will be compared
* later during the
* {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
* method to determine what, if any, animations, should be run.
*
* Subclasses must implement this method. The method should only be called by the * transition system; it is not intended to be called from external classes.
* * @param transitionValues The holder for any values that the Transition * wishes to store. Values are stored in thevalues
field
* of this TransitionValues object and are keyed from
* a String value. For example, to store a view's rotation value,
* a transition might call
* transitionValues.values.put("appname:transitionname:rotation",
* view.getRotation())
. The target view will already be stored
* in
* the transitionValues structure when this method is called.
* @see #captureEndValues(TransitionValues)
* @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
*/
@Override
public abstract void captureStartValues(@NonNull TransitionValues transitionValues);
/**
* This method creates an animation that will be run for this transition
* given the information in the startValues and endValues structures captured
* earlier for the start and end scenes. Subclasses of Transition should override
* this method. The method should only be called by the transition system; it is
* not intended to be called from external classes.
*
* 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 * values that the transition may need to set up initial target values * and construct an appropriate animation. For example, if an overall * Transition is a {@link TransitionSet} consisting of several * child transitions in sequence, then some of the child transitions may * want to set initial values on target views prior to the overall * Transition commencing, to put them in an appropriate state for the * delay between that start and the child Transition start time. For * example, a transition that fades an item in may wish to set the starting * alpha value to 0, to avoid it blinking in prior to the transition * actually starting the animation. This is necessary because the scene * change that triggers the Transition will automatically set the end-scene * on all target views, so a Transition that wants to animate from a * different value should set that value prior to returning from this method.
* *Additionally, a Transition can perform logic to determine whether * the transition needs to run on the given target and start/end values. * For example, a transition that resizes objects on the screen may wish * to avoid running for views which are not present in either the start * or end scenes.
* *If there is an animator created and returned from this method, the
* transition mechanism will apply any applicable duration, startDelay,
* and interpolator to that animation and start it. A return value of
* null
indicates that no animation should run. The default
* implementation returns null.
The method is called for every applicable target object, which is * stored in the {@link TransitionValues#view} field.
* * @param sceneRoot The root of the transition hierarchy. * @param startValues The values for a specific target in the start scene. * @param endValues The values for the target in the end scene. * @return A Animator to be started at the appropriate time in the * overall transition for this scene change. A null value means no animation * should be run. */ @Override @Nullable public Animator createAnimator(@NonNull ViewGroup sceneRoot, @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) { return null; } /** * Whether to add the children of given target to the list of target children * to exclude from this transition. Theexclude
parameter specifies
* whether the target should be added to or removed from the excluded list.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param target The target to ignore when running this transition. * @param exclude Whether to add the target to or remove the target from the * current list of excluded targets. * @return This transition object. * @see #excludeTarget(View, boolean) * @see #excludeChildren(int, boolean) * @see #excludeChildren(Class, boolean) */ @NonNull public Transition excludeChildren(@NonNull View target, boolean exclude) { mImpl.excludeChildren(target, exclude); return this; } /** * Whether to add the children of the given id to the list of targets to exclude * from this transition. Theexclude
parameter specifies whether
* the children of the target should be added to or removed from the excluded list.
* Excluding children in this way provides a simple mechanism for excluding all
* children of specific targets, rather than individually excluding each
* child individually.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param targetId The id of a target whose children should be ignored when running * this transition. * @param exclude Whether to add the target to or remove the target from the * current list of excluded-child targets. * @return This transition object. * @see #excludeTarget(int, boolean) * @see #excludeChildren(View, boolean) * @see #excludeChildren(Class, boolean) */ @NonNull public Transition excludeChildren(@IdRes int targetId, boolean exclude) { mImpl.excludeChildren(targetId, exclude); return this; } /** * Whether to add the given type to the list of types whose children should * be excluded from this transition. Theexclude
parameter
* specifies whether the target type should be added to or removed from
* the excluded list.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param type The type to ignore when running this transition. * @param exclude Whether to add the target type to or remove it from the * current list of excluded target types. * @return This transition object. * @see #excludeTarget(Class, boolean) * @see #excludeChildren(int, boolean) * @see #excludeChildren(View, boolean) */ @NonNull public Transition excludeChildren(@NonNull Class type, boolean exclude) { mImpl.excludeChildren(type, exclude); return this; } /** * Whether to add the given target to the list of targets to exclude from this * transition. Theexclude
parameter specifies whether the target
* should be added to or removed from the excluded list.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param target The target to ignore when running this transition. * @param exclude Whether to add the target to or remove the target from the * current list of excluded targets. * @return This transition object. * @see #excludeChildren(View, boolean) * @see #excludeTarget(int, boolean) * @see #excludeTarget(Class, boolean) */ @NonNull public Transition excludeTarget(@NonNull View target, boolean exclude) { mImpl.excludeTarget(target, exclude); return this; } /** * Whether to add the given id to the list of target ids to exclude from this * transition. Theexclude
parameter specifies whether the target
* should be added to or removed from the excluded list.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param targetId The id of a target to ignore when running this transition. * @param exclude Whether to add the target to or remove the target from the * current list of excluded targets. * @return This transition object. * @see #excludeChildren(int, boolean) * @see #excludeTarget(View, boolean) * @see #excludeTarget(Class, boolean) */ @NonNull public Transition excludeTarget(@IdRes int targetId, boolean exclude) { mImpl.excludeTarget(targetId, exclude); return this; } /** * Whether to add the given type to the list of types to exclude from this * transition. Theexclude
parameter specifies whether the target
* type should be added to or removed from the excluded list.
*
* Excluding targets is a general mechanism for allowing transitions to run on * a view hierarchy while skipping target views that should not be part of * the transition. For example, you may want to avoid animating children * of a specific ListView or Spinner. Views can be excluded either by their * id, or by their instance reference, or by the Class of that view * (eg, {@link Spinner}).
* * @param type The type to ignore when running this transition. * @param exclude Whether to add the target type to or remove it from the * current list of excluded target types. * @return This transition object. * @see #excludeChildren(Class, boolean) * @see #excludeTarget(int, boolean) * @see #excludeTarget(View, boolean) */ @NonNull public Transition excludeTarget(@NonNull Class type, boolean exclude) { mImpl.excludeTarget(type, exclude); 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, in milliseconds, if one has been * set, otherwise returns a negative number. */ public long getDuration() { return mImpl.getDuration(); } /** * Sets the duration of this transition. By default, there is no duration * (indicated by a negative number), which means that the Animator created by * the transition will have its own specified duration. If the duration of a * Transition is set, that duration will override the Animator duration. * * @param duration The length of the animation, in milliseconds. * @return This transition object. * @attr name android:duration */ @NonNull public Transition setDuration(long duration) { mImpl.setDuration(duration); return this; } /** * 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. */ @Nullable public TimeInterpolator getInterpolator() { return mImpl.getInterpolator(); } /** * Sets the interpolator of this transition. By default, the interpolator * is null, which means that the Animator created by the transition * will have its own specified interpolator. If the interpolator of a * Transition is set, that interpolator will override the Animator interpolator. * * @param interpolator The time interpolator used by the transition * @return This transition object. * @attr name android:interpolator */ @NonNull public Transition setInterpolator(@Nullable TimeInterpolator interpolator) { mImpl.setInterpolator(interpolator); return this; } /** * 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 ChangeBounds running on the same target view as another ChangeBounds * should determine whether the old transition is animating to different end values * and should be canceled in favor of the new transition. * *By default, a Transition's name is simply the value of {@link Class#getName()}, * but subclasses are free to override and return something different.
* * @return The name of this transition. */ @NonNull public String getName() { return mImpl.getName(); } /** * 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 startDelay set on this transition, in milliseconds, if one has * been set, otherwise returns a negative number. */ public long getStartDelay() { return mImpl.getStartDelay(); } /** * Sets the startDelay of this transition. By default, there is no delay * (indicated by a negative number), which means that the Animator created by * the transition will have its own specified startDelay. If the delay of a * Transition is set, that delay will override the Animator delay. * * @param startDelay The length of the delay, in milliseconds. * @return This transition object. * @attr name android:startDelay */ @NonNull public Transition setStartDelay(long startDelay) { mImpl.setStartDelay(startDelay); return this; } /** * Returns the array of target IDs that this transition limits itself to * tracking and animating. If the array is null for both this method and * {@link #getTargets()}, then this transition is * not limited to specific views, and will handle changes to any views * in the hierarchy of a scene change. * * @return the list of target IDs */ @NonNull public ListA 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.
* * @return An array of property names as described in the class documentation for * {@link TransitionValues}. The default implementation returnsnull
.
*/
@Nullable
public String[] getTransitionProperties() {
return mImpl.getTransitionProperties();
}
/**
* This method can be called by transitions to get the TransitionValues for
* any particular view during the transition-playing process. This might be
* necessary, for example, to query the before/after state of related views
* for a given transition.
*/
@NonNull
public TransitionValues getTransitionValues(@NonNull View view, boolean start) {
return mImpl.getTransitionValues(view, start);
}
/**
* Removes a listener from the set listening to this animation.
*
* @param listener the listener to be removed from the current set of
* listeners for this transition.
* @return This transition object.
*/
@NonNull
public Transition removeListener(@NonNull TransitionListener listener) {
mImpl.removeListener(listener);
return this;
}
/**
* Removes the given target from the list of targets that this Transition
* is interested in animating.
*
* @param target The target view, must be non-null.
* @return Transition The Transition from which the target is removed.
* Returning the same object makes it easier to chain calls during
* construction, such as
* transitionSet.addTransitions(new Fade()).removeTarget(someView);
*/
@NonNull
public Transition removeTarget(@NonNull View target) {
mImpl.removeTarget(target);
return this;
}
/**
* Removes the given targetId from the list of ids that this Transition
* is interested in animating.
*
* @param targetId The id of a target view, must be a positive number.
* @return The Transition from which the targetId is removed.
* Returning the same object makes it easier to chain calls during
* construction, such as
* transitionSet.addTransitions(new Fade()).removeTargetId(someId);
*/
@NonNull
public Transition removeTarget(@IdRes int targetId) {
mImpl.removeTarget(targetId);
return this;
}
@Override
public String toString() {
return mImpl.toString();
}
/**
* A transition listener receives notifications from a transition.
* Notifications indicate transition lifecycle events.
*/
public interface TransitionListener extends TransitionInterfaceListener