Add curved motion to Transitions.
Bug 15197527 Added two public PathMotions: PatternMotion and ArcMotion. ArcMotion is the algorithm provided by UX. PatternMotion provides a mechanism for using a Path as a pattern. Change-Id: Ie57fd5f4e62269acc1164eced39853a12c52bd77
This commit is contained in:
@@ -825,6 +825,7 @@ package android {
|
||||
field public static final int maxRows = 16843059; // 0x1010133
|
||||
field public static final int maxSdkVersion = 16843377; // 0x1010271
|
||||
field public static final int maxWidth = 16843039; // 0x101011f
|
||||
field public static final int maximumAngle = 16843905; // 0x1010481
|
||||
field public static final int measureAllChildren = 16843018; // 0x101010a
|
||||
field public static final int measureWithLargestChild = 16843476; // 0x10102d4
|
||||
field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
|
||||
@@ -840,6 +841,8 @@ package android {
|
||||
field public static final int minResizeWidth = 16843669; // 0x1010395
|
||||
field public static final int minSdkVersion = 16843276; // 0x101020c
|
||||
field public static final int minWidth = 16843071; // 0x101013f
|
||||
field public static final int minimumHorizontalAngle = 16843903; // 0x101047f
|
||||
field public static final int minimumVerticalAngle = 16843904; // 0x1010480
|
||||
field public static final int mipMap = 16843725; // 0x10103cd
|
||||
field public static final int mirrorForRtl = 16843726; // 0x10103ce
|
||||
field public static final int mode = 16843134; // 0x101017e
|
||||
@@ -30450,12 +30453,26 @@ package android.text.util {
|
||||
|
||||
package android.transition {
|
||||
|
||||
public class ArcMotion extends android.transition.PathMotion {
|
||||
ctor public ArcMotion();
|
||||
ctor public ArcMotion(android.content.Context, android.util.AttributeSet);
|
||||
method public float getMaximumAngle();
|
||||
method public float getMinimumHorizontalAngle();
|
||||
method public float getMinimumVerticalAngle();
|
||||
method public android.graphics.Path getPath(float, float, float, float);
|
||||
method public void setMaximumAngle(float);
|
||||
method public void setMinimumHorizontalAngle(float);
|
||||
method public void setMinimumVerticalAngle(float);
|
||||
}
|
||||
|
||||
public class AutoTransition extends android.transition.TransitionSet {
|
||||
ctor public AutoTransition();
|
||||
ctor public AutoTransition(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
public class ChangeBounds extends android.transition.Transition {
|
||||
ctor public ChangeBounds();
|
||||
ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
method public void setReparent(boolean);
|
||||
@@ -30464,18 +30481,21 @@ package android.transition {
|
||||
|
||||
public class ChangeClipBounds extends android.transition.Transition {
|
||||
ctor public ChangeClipBounds();
|
||||
ctor public ChangeClipBounds(android.content.Context, android.util.AttributeSet);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
}
|
||||
|
||||
public class ChangeImageTransform extends android.transition.Transition {
|
||||
ctor public ChangeImageTransform();
|
||||
ctor public ChangeImageTransform(android.content.Context, android.util.AttributeSet);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
}
|
||||
|
||||
public class ChangeTransform extends android.transition.Transition {
|
||||
ctor public ChangeTransform();
|
||||
ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
}
|
||||
@@ -30488,15 +30508,32 @@ package android.transition {
|
||||
|
||||
public class Explode extends android.transition.Visibility {
|
||||
ctor public Explode();
|
||||
ctor public Explode(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
public class Fade extends android.transition.Visibility {
|
||||
ctor public Fade();
|
||||
ctor public Fade(int);
|
||||
ctor public Fade(android.content.Context, android.util.AttributeSet);
|
||||
field public static final int IN = 1; // 0x1
|
||||
field public static final int OUT = 2; // 0x2
|
||||
}
|
||||
|
||||
public abstract class PathMotion {
|
||||
ctor public PathMotion();
|
||||
ctor public PathMotion(android.content.Context, android.util.AttributeSet);
|
||||
method public abstract android.graphics.Path getPath(float, float, float, float);
|
||||
}
|
||||
|
||||
public class PatternMotion extends android.transition.PathMotion {
|
||||
ctor public PatternMotion();
|
||||
ctor public PatternMotion(android.content.Context, android.util.AttributeSet);
|
||||
ctor public PatternMotion(android.graphics.Path);
|
||||
method public android.graphics.Path getPath(float, float, float, float);
|
||||
method public android.graphics.Path getPattern();
|
||||
method public void setPattern(android.graphics.Path);
|
||||
}
|
||||
|
||||
public final class Scene {
|
||||
ctor public Scene(android.view.ViewGroup);
|
||||
ctor public Scene(android.view.ViewGroup, android.view.View);
|
||||
@@ -30519,11 +30556,14 @@ package android.transition {
|
||||
public class Slide extends android.transition.Visibility {
|
||||
ctor public Slide();
|
||||
ctor public Slide(int);
|
||||
ctor public Slide(android.content.Context, android.util.AttributeSet);
|
||||
method public int getSlideEdge();
|
||||
method public void setSlideEdge(int);
|
||||
}
|
||||
|
||||
public abstract class Transition implements java.lang.Cloneable {
|
||||
ctor public Transition();
|
||||
ctor public Transition(android.content.Context, android.util.AttributeSet);
|
||||
method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
|
||||
method public android.transition.Transition addTarget(int);
|
||||
method public android.transition.Transition addTarget(java.lang.String);
|
||||
@@ -30546,6 +30586,7 @@ package android.transition {
|
||||
method public android.transition.Transition.EpicenterCallback getEpicenterCallback();
|
||||
method public android.animation.TimeInterpolator getInterpolator();
|
||||
method public java.lang.String getName();
|
||||
method public android.transition.PathMotion getPathMotion();
|
||||
method public android.transition.TransitionPropagation getPropagation();
|
||||
method public long getStartDelay();
|
||||
method public java.util.List<java.lang.Integer> getTargetIds();
|
||||
@@ -30563,6 +30604,7 @@ package android.transition {
|
||||
method public void setEpicenterCallback(android.transition.Transition.EpicenterCallback);
|
||||
method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
|
||||
method public void setMatchOrder(int...);
|
||||
method public void setPathMotion(android.transition.PathMotion);
|
||||
method public void setPropagation(android.transition.TransitionPropagation);
|
||||
method public android.transition.Transition setStartDelay(long);
|
||||
field public static final int MATCH_ID = 3; // 0x3
|
||||
@@ -30610,6 +30652,7 @@ package android.transition {
|
||||
|
||||
public class TransitionSet extends android.transition.Transition {
|
||||
ctor public TransitionSet();
|
||||
ctor public TransitionSet(android.content.Context, android.util.AttributeSet);
|
||||
method public android.transition.TransitionSet addTransition(android.transition.Transition);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
@@ -30628,8 +30671,10 @@ package android.transition {
|
||||
|
||||
public abstract class Visibility extends android.transition.Transition {
|
||||
ctor public Visibility();
|
||||
ctor public Visibility(android.content.Context, android.util.AttributeSet);
|
||||
method public void captureEndValues(android.transition.TransitionValues);
|
||||
method public void captureStartValues(android.transition.TransitionValues);
|
||||
method public int getMode();
|
||||
method public boolean isVisible(android.transition.TransitionValues);
|
||||
method public android.animation.Animator onAppear(android.view.ViewGroup, android.transition.TransitionValues, int, android.transition.TransitionValues, int);
|
||||
method public android.animation.Animator onAppear(android.view.ViewGroup, android.view.View, android.transition.TransitionValues, android.transition.TransitionValues);
|
||||
|
||||
272
core/java/android/transition/ArcMotion.java
Normal file
272
core/java/android/transition/ArcMotion.java
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatMath;
|
||||
|
||||
/**
|
||||
* A PathMotion that generates a curved path along an arc on an imaginary circle containing
|
||||
* the two points. If the horizontal distance between the points is less than the vertical
|
||||
* distance, then the circle's center point will be horizontally aligned with the end point. If the
|
||||
* vertical distance is less than the horizontal distance then the circle's center point
|
||||
* will be vertically aligned with the end point.
|
||||
* <p>
|
||||
* When the two points are near horizontal or vertical, the curve of the motion will be
|
||||
* small as the center of the circle will be far from both points. To force curvature of
|
||||
* the path, {@link #setMinimumHorizontalAngle(float)} and
|
||||
* {@link #setMinimumVerticalAngle(float)} may be used to set the minimum angle of the
|
||||
* arc between two points.
|
||||
* </p>
|
||||
* <p>This may be used in XML as an element inside a transition.</p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* <changeBounds>
|
||||
* <arcMotion android:minimumHorizontalAngle="15"
|
||||
* android:minimumVerticalAngle="0" android:maximumAngle="90"/>
|
||||
* </changeBounds>
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class ArcMotion extends PathMotion {
|
||||
|
||||
private static final float DEFAULT_MIN_ANGLE_DEGREES = 0;
|
||||
private static final float DEFAULT_MAX_ANGLE_DEGREES = 70;
|
||||
private static final float DEFAULT_MAX_TANGENT = (float)
|
||||
Math.tan(Math.toRadians(DEFAULT_MAX_ANGLE_DEGREES/2));
|
||||
|
||||
private float mMinimumHorizontalAngle = 0;
|
||||
private float mMinimumVerticalAngle = 0;
|
||||
private float mMaximumAngle = DEFAULT_MAX_ANGLE_DEGREES;
|
||||
private float mMinimumHorizontalTangent = 0;
|
||||
private float mMinimumVerticalTangent = 0;
|
||||
private float mMaximumTangent = DEFAULT_MAX_TANGENT;
|
||||
|
||||
public ArcMotion() {}
|
||||
|
||||
public ArcMotion(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcMotion);
|
||||
float minimumVerticalAngle = a.getFloat(R.styleable.ArcMotion_minimumVerticalAngle,
|
||||
DEFAULT_MIN_ANGLE_DEGREES);
|
||||
setMinimumVerticalAngle(minimumVerticalAngle);
|
||||
float minimumHorizontalAngle = a.getFloat(R.styleable.ArcMotion_minimumHorizontalAngle,
|
||||
DEFAULT_MIN_ANGLE_DEGREES);
|
||||
setMinimumHorizontalAngle(minimumHorizontalAngle);
|
||||
float maximumAngle = a.getFloat(R.styleable.ArcMotion_maximumAngle,
|
||||
DEFAULT_MAX_ANGLE_DEGREES);
|
||||
setMaximumAngle(maximumAngle);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum arc along the circle between two points aligned near horizontally.
|
||||
* When start and end points are close to horizontal, the calculated center point of the
|
||||
* circle will be far from both points, giving a near straight path between the points.
|
||||
* By setting a minimum angle, this forces the center point to be closer and give an
|
||||
* exaggerated curve to the path.
|
||||
* <p>The default value is 0.</p>
|
||||
*
|
||||
* @param angleInDegrees The minimum angle of the arc on a circle describing the Path
|
||||
* between two nearly horizontally-separated points.
|
||||
* @attr ref android.R.styleable#ArcMotion_minimumHorizontalAngle
|
||||
*/
|
||||
public void setMinimumHorizontalAngle(float angleInDegrees) {
|
||||
mMinimumHorizontalAngle = angleInDegrees;
|
||||
mMinimumHorizontalTangent = toTangent(angleInDegrees);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum arc along the circle between two points aligned near horizontally.
|
||||
* When start and end points are close to horizontal, the calculated center point of the
|
||||
* circle will be far from both points, giving a near straight path between the points.
|
||||
* By setting a minimum angle, this forces the center point to be closer and give an
|
||||
* exaggerated curve to the path.
|
||||
* <p>The default value is 0.</p>
|
||||
*
|
||||
* @return The minimum arc along the circle between two points aligned near horizontally.
|
||||
* @attr ref android.R.styleable#ArcMotion_minimumHorizontalAngle
|
||||
*/
|
||||
public float getMinimumHorizontalAngle() {
|
||||
return mMinimumHorizontalAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum arc along the circle between two points aligned near vertically.
|
||||
* When start and end points are close to vertical, the calculated center point of the
|
||||
* circle will be far from both points, giving a near straight path between the points.
|
||||
* By setting a minimum angle, this forces the center point to be closer and give an
|
||||
* exaggerated curve to the path.
|
||||
* <p>The default value is 0.</p>
|
||||
*
|
||||
* @param angleInDegrees The minimum angle of the arc on a circle describing the Path
|
||||
* between two nearly vertically-separated points.
|
||||
* @attr ref android.R.styleable#ArcMotion_minimumVerticalAngle
|
||||
*/
|
||||
public void setMinimumVerticalAngle(float angleInDegrees) {
|
||||
mMinimumVerticalAngle = angleInDegrees;
|
||||
mMinimumVerticalTangent = toTangent(angleInDegrees);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum arc along the circle between two points aligned near vertically.
|
||||
* When start and end points are close to vertical, the calculated center point of the
|
||||
* circle will be far from both points, giving a near straight path between the points.
|
||||
* By setting a minimum angle, this forces the center point to be closer and give an
|
||||
* exaggerated curve to the path.
|
||||
* <p>The default value is 0.</p>
|
||||
*
|
||||
* @return The minimum angle of the arc on a circle describing the Path
|
||||
* between two nearly vertically-separated points.
|
||||
* @attr ref android.R.styleable#ArcMotion_minimumVerticalAngle
|
||||
*/
|
||||
public float getMinimumVerticalAngle() {
|
||||
return mMinimumVerticalAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum arc along the circle between two points. When start and end points
|
||||
* have close to equal x and y differences, the curve between them is large. This forces
|
||||
* the curved path to have an arc of at most the given angle.
|
||||
* <p>The default value is 70 degrees.</p>
|
||||
*
|
||||
* @param angleInDegrees The maximum angle of the arc on a circle describing the Path
|
||||
* between the start and end points.
|
||||
* @attr ref android.R.styleable#ArcMotion_maximumAngle
|
||||
*/
|
||||
public void setMaximumAngle(float angleInDegrees) {
|
||||
mMaximumAngle = angleInDegrees;
|
||||
mMaximumTangent = toTangent(angleInDegrees);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum arc along the circle between two points. When start and end points
|
||||
* have close to equal x and y differences, the curve between them is large. This forces
|
||||
* the curved path to have an arc of at most the given angle.
|
||||
* <p>The default value is 70 degrees.</p>
|
||||
*
|
||||
* @return The maximum angle of the arc on a circle describing the Path
|
||||
* between the start and end points.
|
||||
* @attr ref android.R.styleable#ArcMotion_maximumAngle
|
||||
*/
|
||||
public float getMaximumAngle() {
|
||||
return mMaximumAngle;
|
||||
}
|
||||
|
||||
private static float toTangent(float arcInDegrees) {
|
||||
if (arcInDegrees < 0 || arcInDegrees > 90) {
|
||||
throw new IllegalArgumentException("Arc must be between 0 and 90 degrees");
|
||||
}
|
||||
return (float) Math.tan(Math.toRadians(arcInDegrees / 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(float startX, float startY, float endX, float endY) {
|
||||
// Here's a little ascii art to show how this is calculated:
|
||||
// c---------- b
|
||||
// \ / |
|
||||
// \ d |
|
||||
// \ / e
|
||||
// a----f
|
||||
// This diagram assumes that the horizontal distance is less than the vertical
|
||||
// distance between The start point (a) and end point (b).
|
||||
// d is the midpoint between a and b. c is the center point of the circle with
|
||||
// This path is formed by assuming that start and end points are in
|
||||
// an arc on a circle. The end point is centered in the circle vertically
|
||||
// and start is a point on the circle.
|
||||
|
||||
// Triangles bfa and bde form similar right triangles. The control points
|
||||
// for the cubic Bezier arc path are the midpoints between a and e and e and b.
|
||||
|
||||
Path path = new Path();
|
||||
path.moveTo(startX, startY);
|
||||
|
||||
float ex;
|
||||
float ey;
|
||||
if (startY == endY) {
|
||||
ex = (startX + endX) / 2;
|
||||
ey = startY + mMinimumHorizontalTangent * Math.abs(endX - startX) / 2;
|
||||
} else if (startX == endX) {
|
||||
ex = startX + mMinimumVerticalTangent * Math.abs(endY - startY) / 2;
|
||||
ey = (startY + endY) / 2;
|
||||
} else {
|
||||
float deltaX = endX - startX;
|
||||
float deltaY = startY - endY; // Y is inverted compared to diagram above.
|
||||
// hypotenuse squared.
|
||||
float h2 = deltaX * deltaX + deltaY * deltaY;
|
||||
|
||||
// Midpoint between start and end
|
||||
float dx = (startX + endX) / 2;
|
||||
float dy = (startY + endY) / 2;
|
||||
|
||||
// Distance squared between end point and mid point is (1/2 hypotenuse)^2
|
||||
float midDist2 = h2 * 0.25f;
|
||||
|
||||
float minimumArcDist2 = 0;
|
||||
|
||||
if (Math.abs(deltaX) < Math.abs(deltaY)) {
|
||||
// Similar triangles bfa and bde mean that (ab/fb = eb/bd)
|
||||
// Therefore, eb = ab * bd / fb
|
||||
// ab = hypotenuse
|
||||
// bd = hypotenuse/2
|
||||
// fb = deltaY
|
||||
float eDistY = h2 / (2 * deltaY);
|
||||
ey = endY + eDistY;
|
||||
ex = endX;
|
||||
|
||||
minimumArcDist2 = midDist2 * mMinimumVerticalTangent
|
||||
* mMinimumVerticalTangent;
|
||||
} else {
|
||||
// Same as above, but flip X & Y
|
||||
float eDistX = h2 / (2 * deltaX);
|
||||
ex = endX + eDistX;
|
||||
ey = endY;
|
||||
|
||||
minimumArcDist2 = midDist2 * mMinimumHorizontalTangent
|
||||
* mMinimumHorizontalTangent;
|
||||
}
|
||||
float arcDistX = dx - ex;
|
||||
float arcDistY = dy - ey;
|
||||
float arcDist2 = arcDistX * arcDistX + arcDistY * arcDistY;
|
||||
|
||||
float maximumArcDist2 = midDist2 * mMaximumTangent * mMaximumTangent;
|
||||
|
||||
float newArcDistance2 = 0;
|
||||
if (arcDist2 < minimumArcDist2) {
|
||||
newArcDistance2 = minimumArcDist2;
|
||||
} else if (arcDist2 > maximumArcDist2) {
|
||||
newArcDistance2 = maximumArcDist2;
|
||||
}
|
||||
if (newArcDistance2 != 0) {
|
||||
float ratio2 = newArcDistance2 / arcDist2;
|
||||
float ratio = FloatMath.sqrt(ratio2);
|
||||
ex = dx + (ratio * (ex - dx));
|
||||
ey = dy + (ratio * (ey - dy));
|
||||
}
|
||||
}
|
||||
float controlX1 = (startX + ex) / 2;
|
||||
float controlY1 = (startY + ey) / 2;
|
||||
float controlX2 = (ex + endX) / 2;
|
||||
float controlY2 = (ey + endY) / 2;
|
||||
path.cubicTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* Utility class for creating a default transition that automatically fades,
|
||||
* moves, and resizes views during a scene change.
|
||||
@@ -33,6 +36,15 @@ public class AutoTransition extends TransitionSet {
|
||||
*
|
||||
*/
|
||||
public AutoTransition() {
|
||||
init();
|
||||
}
|
||||
|
||||
public AutoTransition(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOrdering(ORDERING_SEQUENTIAL);
|
||||
addTransition(new Fade(Fade.OUT)).
|
||||
addTransition(new ChangeBounds()).
|
||||
|
||||
@@ -16,15 +16,24 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import android.animation.TypeConverter;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.RectEvaluator;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -51,6 +60,24 @@ public class ChangeBounds extends Transition {
|
||||
PROPNAME_WINDOW_Y
|
||||
};
|
||||
|
||||
private static final Property<Drawable, PointF> DRAWABLE_ORIGIN_PROPERTY =
|
||||
new Property<Drawable, PointF>(PointF.class, "boundsOrigin") {
|
||||
private Rect mBounds = new Rect();
|
||||
|
||||
@Override
|
||||
public void set(Drawable object, PointF value) {
|
||||
object.copyBounds(mBounds);
|
||||
mBounds.offsetTo(Math.round(value.x), Math.round(value.y));
|
||||
object.setBounds(mBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointF get(Drawable object) {
|
||||
object.copyBounds(mBounds);
|
||||
return new PointF(mBounds.left, mBounds.top);
|
||||
}
|
||||
};
|
||||
|
||||
int[] tempLocation = new int[2];
|
||||
boolean mResizeClip = false;
|
||||
boolean mReparent = false;
|
||||
@@ -58,6 +85,12 @@ public class ChangeBounds extends Transition {
|
||||
|
||||
private static RectEvaluator sRectEvaluator = new RectEvaluator();
|
||||
|
||||
public ChangeBounds() {}
|
||||
|
||||
public ChangeBounds(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
@@ -138,34 +171,29 @@ public class ChangeBounds extends Transition {
|
||||
int endHeight = endBottom - endTop;
|
||||
int numChanges = 0;
|
||||
if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
|
||||
if (startLeft != endLeft) ++numChanges;
|
||||
if (startTop != endTop) ++numChanges;
|
||||
if (startRight != endRight) ++numChanges;
|
||||
if (startBottom != endBottom) ++numChanges;
|
||||
if (startLeft != endLeft || startTop != endTop) ++numChanges;
|
||||
if (startRight != endRight || startBottom != endBottom) ++numChanges;
|
||||
}
|
||||
if (numChanges > 0) {
|
||||
if (!mResizeClip) {
|
||||
PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
|
||||
int pvhIndex = 0;
|
||||
if (startLeft != endLeft) view.setLeft(startLeft);
|
||||
if (startTop != endTop) view.setTop(startTop);
|
||||
if (startRight != endRight) view.setRight(startRight);
|
||||
if (startBottom != endBottom) view.setBottom(startBottom);
|
||||
if (startLeft != endLeft) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft);
|
||||
ObjectAnimator topLeftAnimator = null;
|
||||
if (startLeft != endLeft || startTop != endTop) {
|
||||
Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
|
||||
endLeft, endTop);
|
||||
topLeftAnimator = ObjectAnimator.ofInt(view, "left", "top", topLeftPath);
|
||||
}
|
||||
if (startTop != endTop) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop);
|
||||
ObjectAnimator bottomRightAnimator = null;
|
||||
if (startRight != endRight || startBottom != endBottom) {
|
||||
Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
|
||||
endRight, endBottom);
|
||||
bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
|
||||
bottomRightPath);
|
||||
}
|
||||
if (startRight != endRight) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right",
|
||||
startRight, endRight);
|
||||
}
|
||||
if (startBottom != endBottom) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom",
|
||||
startBottom, endBottom);
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
|
||||
Animator anim = mergeAnimators(topLeftAnimator, bottomRightAnimator);
|
||||
if (view.getParent() instanceof ViewGroup) {
|
||||
final ViewGroup parent = (ViewGroup) view.getParent();
|
||||
parent.suppressLayout(true);
|
||||
@@ -215,23 +243,20 @@ public class ChangeBounds extends Transition {
|
||||
if (transXDelta != 0) numChanges++;
|
||||
if (transYDelta != 0) numChanges++;
|
||||
if (widthDelta != 0 || heightDelta != 0) numChanges++;
|
||||
PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
|
||||
int pvhIndex = 0;
|
||||
if (transXDelta != 0) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX",
|
||||
view.getTranslationX(), 0);
|
||||
}
|
||||
if (transYDelta != 0) {
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY",
|
||||
view.getTranslationY(), 0);
|
||||
ObjectAnimator translationAnimator = null;
|
||||
if (transXDelta != 0 || transYDelta != 0) {
|
||||
Path topLeftPath = getPathMotion().getPath(0, 0, transXDelta, transYDelta);
|
||||
translationAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X,
|
||||
View.TRANSLATION_Y, topLeftPath);
|
||||
}
|
||||
ObjectAnimator clipAnimator = null;
|
||||
if (widthDelta != 0 || heightDelta != 0) {
|
||||
Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
|
||||
Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
|
||||
pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds",
|
||||
sRectEvaluator, tempStartBounds, tempEndBounds);
|
||||
clipAnimator = ObjectAnimator.ofObject(view, "clipBounds", sRectEvaluator,
|
||||
tempStartBounds, tempEndBounds);
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
|
||||
Animator anim = mergeAnimators(translationAnimator, clipAnimator);
|
||||
if (view.getParent() instanceof ViewGroup) {
|
||||
final ViewGroup parent = (ViewGroup) view.getParent();
|
||||
parent.suppressLayout(true);
|
||||
@@ -287,14 +312,11 @@ public class ChangeBounds extends Transition {
|
||||
final BitmapDrawable drawable = new BitmapDrawable(bitmap);
|
||||
view.setVisibility(View.INVISIBLE);
|
||||
sceneRoot.getOverlay().add(drawable);
|
||||
Rect startBounds1 = new Rect(startX - tempLocation[0], startY - tempLocation[1],
|
||||
startX - tempLocation[0] + view.getWidth(),
|
||||
startY - tempLocation[1] + view.getHeight());
|
||||
Rect endBounds1 = new Rect(endX - tempLocation[0], endY - tempLocation[1],
|
||||
endX - tempLocation[0] + view.getWidth(),
|
||||
endY - tempLocation[1] + view.getHeight());
|
||||
ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds",
|
||||
sRectEvaluator, startBounds1, endBounds1);
|
||||
Path topLeftPath = getPathMotion().getPath(startX - tempLocation[0],
|
||||
startY - tempLocation[1], endX - tempLocation[0], endY - tempLocation[1]);
|
||||
PropertyValuesHolder origin = PropertyValuesHolder.ofObject(
|
||||
DRAWABLE_ORIGIN_PROPERTY, null, topLeftPath);
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, origin);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
@@ -307,4 +329,16 @@ public class ChangeBounds extends Transition {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Animator mergeAnimators(Animator animator1, Animator animator2) {
|
||||
if (animator1 == null) {
|
||||
return animator2;
|
||||
} else if (animator2 == null) {
|
||||
return animator1;
|
||||
} else {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(animator1, animator2);
|
||||
return animatorSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package android.transition;
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.RectEvaluator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -37,6 +39,12 @@ public class ChangeClipBounds extends Transition {
|
||||
PROPNAME_CLIP,
|
||||
};
|
||||
|
||||
public ChangeClipBounds() {}
|
||||
|
||||
public ChangeClipBounds(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
|
||||
@@ -19,9 +19,11 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -37,10 +39,10 @@ import java.util.Map;
|
||||
*/
|
||||
public class ChangeImageTransform extends Transition {
|
||||
|
||||
private static final String TAG = "ChangeScaleType";
|
||||
private static final String TAG = "ChangeImageTransform";
|
||||
|
||||
private static final String PROPNAME_MATRIX = "android:changeScaleType:matrix";
|
||||
private static final String PROPNAME_BOUNDS = "android:changeScaleType:bounds";
|
||||
private static final String PROPNAME_MATRIX = "android:changeImageTransform:matrix";
|
||||
private static final String PROPNAME_BOUNDS = "android:changeImageTransform:bounds";
|
||||
|
||||
private static final String[] sTransitionProperties = {
|
||||
PROPNAME_MATRIX,
|
||||
@@ -67,6 +69,12 @@ public class ChangeImageTransform extends Transition {
|
||||
}
|
||||
};
|
||||
|
||||
public ChangeImageTransform() {}
|
||||
|
||||
public ChangeImageTransform(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
View view = transitionValues.view;
|
||||
if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.transition;
|
||||
import android.animation.Animator;
|
||||
import android.animation.FloatArrayEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Property;
|
||||
import android.view.View;
|
||||
@@ -76,6 +78,12 @@ public class ChangeTransform extends Transition {
|
||||
}
|
||||
};
|
||||
|
||||
public ChangeTransform() {}
|
||||
|
||||
public ChangeTransform(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
|
||||
@@ -19,7 +19,9 @@ import com.android.internal.R;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatMath;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -48,6 +50,10 @@ public class Explode extends Visibility {
|
||||
setPropagation(new CircularPropagation());
|
||||
}
|
||||
|
||||
public Explode(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
View view = transitionValues.view;
|
||||
view.getLocationOnScreen(mTempLoc);
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -93,6 +98,13 @@ public class Fade extends Visibility {
|
||||
setMode(fadingMode);
|
||||
}
|
||||
|
||||
public Fade(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Fade);
|
||||
int fadingMode = a.getInt(R.styleable.Fade_fadingMode, getMode());
|
||||
setMode(fadingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to handle creating and running the Animator.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package android.transition;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* TO BE REMOVED.
|
||||
* Use ChangeImageTransform + ChangeBounds instead.
|
||||
@@ -23,6 +26,15 @@ package android.transition;
|
||||
public class MoveImage extends TransitionSet {
|
||||
|
||||
public MoveImage() {
|
||||
init();
|
||||
}
|
||||
|
||||
public MoveImage(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
addTransition(new ChangeBounds());
|
||||
addTransition(new ChangeClipBounds());
|
||||
addTransition(new ChangeTransform());
|
||||
|
||||
59
core/java/android/transition/PathMotion.java
Normal file
59
core/java/android/transition/PathMotion.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.transition;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* This base class can be extended to provide motion along a Path to Transitions.
|
||||
*
|
||||
* <p>
|
||||
* Transitions such as {@link android.transition.ChangeBounds} move Views, typically
|
||||
* in a straight path between the start and end positions. Applications that desire to
|
||||
* have these motions move in a curve can change how Views interpolate in two dimensions
|
||||
* by extending PathMotion and implementing {@link #getPath(float, float, float, float)}.
|
||||
* </p>
|
||||
* <p>This may be used in XML as an element inside a transition.</p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* <changeBounds>
|
||||
* <pathMotion class="my.app.transition.MyPathMotion"/>
|
||||
* </changeBounds>
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public abstract class PathMotion {
|
||||
|
||||
public PathMotion() {}
|
||||
|
||||
public PathMotion(Context context, AttributeSet attrs) {}
|
||||
|
||||
/**
|
||||
* Provide a Path to interpolate between two points <code>(startX, startY)</code> and
|
||||
* <code>(endX, endY)</code>. This allows controlled curved motion along two dimensions.
|
||||
*
|
||||
* @param startX The x coordinate of the starting point.
|
||||
* @param startY The y coordinate of the starting point.
|
||||
* @param endX The x coordinate of the ending point.
|
||||
* @param endY The y coordinate of the ending point.
|
||||
* @return A Path along which the points should be interpolated. The returned Path
|
||||
* must start at point <code>(startX, startY)</code>, typically using
|
||||
* {@link android.graphics.Path#moveTo(float, float)} and end at <code>(endX, endY)</code>.
|
||||
*/
|
||||
public abstract Path getPath(float startX, float startY, float endX, float endY);
|
||||
}
|
||||
149
core/java/android/transition/PatternMotion.java
Normal file
149
core/java/android/transition/PatternMotion.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PathMeasure;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatMath;
|
||||
import android.util.PathParser;
|
||||
|
||||
/**
|
||||
* A PathMotion that takes a Path pattern and applies it to the separation between two points.
|
||||
* The starting point of the Path will be moved to the origin and the end point will be scaled
|
||||
* and rotated so that it matches with the target end point.
|
||||
* <p>This may be used in XML as an element inside a transition.</p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* <changeBounds>
|
||||
* <patternMotion android:pathData="M0 0 L0 100 L100 100"/>
|
||||
* </changeBounds>
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class PatternMotion extends PathMotion {
|
||||
|
||||
private Path mOriginalPattern;
|
||||
|
||||
private final Path mPattern = new Path();
|
||||
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
|
||||
/**
|
||||
* Constructs a PatternMotion with a straight-line pattern.
|
||||
*/
|
||||
public PatternMotion() {
|
||||
mPattern.lineTo(1, 0);
|
||||
mOriginalPattern = mPattern;
|
||||
}
|
||||
|
||||
public PatternMotion(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PatternMotion);
|
||||
try {
|
||||
String pathData = a.getString(R.styleable.PatternMotion_pathData);
|
||||
if (pathData == null) {
|
||||
throw new RuntimeException("pathData must be supplied for patternMotion");
|
||||
}
|
||||
Path pattern = PathParser.createPathFromPathData(pathData);
|
||||
setPattern(pattern);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PatternMotion with the Path defining a pattern of motion between two coordinates.
|
||||
* The pattern will be translated, rotated, and scaled to fit between the start and end points.
|
||||
* The pattern must not be empty and must have the end point differ from the start point.
|
||||
*
|
||||
* @param pattern A Path to be used as a pattern for two-dimensional motion.
|
||||
*/
|
||||
public PatternMotion(Path pattern) {
|
||||
setPattern(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Path defining a pattern of motion between two coordinates.
|
||||
* The pattern will be translated, rotated, and scaled to fit between the start and end points.
|
||||
* The pattern must not be empty and must have the end point differ from the start point.
|
||||
*
|
||||
* @return the Path defining a pattern of motion between two coordinates.
|
||||
* @attr ref android.R.styleable#PatternMotion_pathData
|
||||
*/
|
||||
public Path getPattern() {
|
||||
return mOriginalPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Path defining a pattern of motion between two coordinates.
|
||||
* The pattern will be translated, rotated, and scaled to fit between the start and end points.
|
||||
* The pattern must not be empty and must have the end point differ from the start point.
|
||||
*
|
||||
* @param pattern A Path to be used as a pattern for two-dimensional motion.
|
||||
* @attr ref android.R.styleable#PatternMotion_pathData
|
||||
*/
|
||||
public void setPattern(Path pattern) {
|
||||
PathMeasure pathMeasure = new PathMeasure(pattern, false);
|
||||
float length = pathMeasure.getLength();
|
||||
float[] pos = new float[2];
|
||||
pathMeasure.getPosTan(length, pos, null);
|
||||
float endX = pos[0];
|
||||
float endY = pos[1];
|
||||
pathMeasure.getPosTan(0, pos, null);
|
||||
float startX = pos[0];
|
||||
float startY = pos[1];
|
||||
|
||||
if (startX == endX && startY == endY) {
|
||||
throw new IllegalArgumentException("pattern must not end at the starting point");
|
||||
}
|
||||
|
||||
mTempMatrix.setTranslate(-startX, -startY);
|
||||
float dx = endX - startX;
|
||||
float dy = endY - startY;
|
||||
float distance = distance(dx, dy);
|
||||
float scale = 1 / distance;
|
||||
mTempMatrix.postScale(scale, scale);
|
||||
double angle = Math.atan2(dy, dx);
|
||||
mTempMatrix.postRotate((float) Math.toDegrees(-angle));
|
||||
pattern.transform(mTempMatrix, mPattern);
|
||||
mOriginalPattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(float startX, float startY, float endX, float endY) {
|
||||
float dx = endX - startX;
|
||||
float dy = endY - startY;
|
||||
float length = distance(dx, dy);
|
||||
double angle = Math.atan2(dy, dx);
|
||||
|
||||
mTempMatrix.setScale(length, length);
|
||||
mTempMatrix.postRotate((float) Math.toDegrees(angle));
|
||||
mTempMatrix.postTranslate(startX, startY);
|
||||
Path path = new Path();
|
||||
mPattern.transform(mTempMatrix, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
private static float distance(float x, float y) {
|
||||
return FloatMath.sqrt((x * x) + (y * y));
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,10 @@ package android.transition;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
@@ -40,6 +42,12 @@ public class Recolor extends Transition {
|
||||
private static final String PROPNAME_BACKGROUND = "android:recolor:background";
|
||||
private static final String PROPNAME_TEXT_COLOR = "android:recolor:textColor";
|
||||
|
||||
public Recolor() {}
|
||||
|
||||
public Recolor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
transitionValues.values.put(PROPNAME_BACKGROUND, transitionValues.view.getBackground());
|
||||
if (transitionValues.view instanceof TextView) {
|
||||
|
||||
@@ -17,11 +17,15 @@ package android.transition;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* This transition tracks changes to the visibility of target views in the
|
||||
@@ -38,6 +42,7 @@ public class Slide extends Visibility {
|
||||
private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
|
||||
private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
|
||||
private CalculateSlide mSlideCalculator = sCalculateBottom;
|
||||
private int mSlideEdge = Gravity.BOTTOM;
|
||||
|
||||
private interface CalculateSlide {
|
||||
|
||||
@@ -107,6 +112,14 @@ public class Slide extends Visibility {
|
||||
setSlideEdge(slideEdge);
|
||||
}
|
||||
|
||||
public Slide(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Slide);
|
||||
int edge = a.getInt(R.styleable.Slide_slideEdge, Gravity.BOTTOM);
|
||||
a.recycle();
|
||||
setSlideEdge(edge);
|
||||
}
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
View view = transitionValues.view;
|
||||
int[] position = new int[2];
|
||||
@@ -132,6 +145,7 @@ public class Slide extends Visibility {
|
||||
* @param slideEdge The edge of the scene to use for Views appearing and disappearing. One of
|
||||
* {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
|
||||
* {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}.
|
||||
* @attr ref android.R.styleable#Slide_slideEdge
|
||||
*/
|
||||
public void setSlideEdge(int slideEdge) {
|
||||
switch (slideEdge) {
|
||||
@@ -150,11 +164,24 @@ public class Slide extends Visibility {
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid slide direction");
|
||||
}
|
||||
mSlideEdge = slideEdge;
|
||||
SidePropagation propagation = new SidePropagation();
|
||||
propagation.setSide(slideEdge);
|
||||
setPropagation(propagation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edge that Views appear and disappear from.
|
||||
*
|
||||
* @return the edge of the scene to use for Views appearing and disappearing. One of
|
||||
* {@link android.view.Gravity#LEFT}, {@link android.view.Gravity#TOP},
|
||||
* {@link android.view.Gravity#RIGHT}, {@link android.view.Gravity#BOTTOM}.
|
||||
* @attr ref android.R.styleable#Slide_slideEdge
|
||||
*/
|
||||
public int getSlideEdge() {
|
||||
return mSlideEdge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator onAppear(ViewGroup sceneRoot, View view,
|
||||
TransitionValues startValues, TransitionValues endValues) {
|
||||
|
||||
@@ -19,23 +19,32 @@ package android.transition;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseLongArray;
|
||||
import android.view.InflateException;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.TextureView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOverlay;
|
||||
import android.view.WindowId;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* A Transition holds information about animations that will be run on its
|
||||
@@ -139,6 +148,13 @@ public abstract class Transition implements Cloneable {
|
||||
|
||||
private static final int MATCH_LAST = MATCH_ITEM_ID;
|
||||
|
||||
private static final String MATCH_INSTANCE_STR = "instance";
|
||||
private static final String MATCH_NAME_STR = "name";
|
||||
/** To be removed before L release */
|
||||
private static final String MATCH_VIEW_NAME_STR = "viewName";
|
||||
private static final String MATCH_ID_STR = "id";
|
||||
private static final String MATCH_ITEM_ID_STR = "itemId";
|
||||
|
||||
private static final int[] DEFAULT_MATCH_ORDER = {
|
||||
MATCH_NAME,
|
||||
MATCH_INSTANCE,
|
||||
@@ -146,6 +162,16 @@ public abstract class Transition implements Cloneable {
|
||||
MATCH_ITEM_ID,
|
||||
};
|
||||
|
||||
private static final PathMotion STRAIGHT_PATH_MOTION = new PathMotion() {
|
||||
@Override
|
||||
public Path getPath(float startX, float startY, float endX, float endY) {
|
||||
Path path = new Path();
|
||||
path.moveTo(startX, startY);
|
||||
path.lineTo(endX, endY);
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
private String mName = getClass().getName();
|
||||
|
||||
long mStartDelay = -1;
|
||||
@@ -215,6 +241,10 @@ public abstract class Transition implements Cloneable {
|
||||
// transitionNames.
|
||||
ArrayMap<String, String> mNameOverrides;
|
||||
|
||||
// The function used to interpolate along two-dimensional points. Typically used
|
||||
// for adding curves to x/y View motion.
|
||||
private PathMotion mPathMotion = STRAIGHT_PATH_MOTION;
|
||||
|
||||
/**
|
||||
* Constructs a Transition object with no target objects. A transition with
|
||||
* no targets defaults to running on all target objects in the scene hierarchy
|
||||
@@ -223,6 +253,66 @@ public abstract class Transition implements Cloneable {
|
||||
*/
|
||||
public Transition() {}
|
||||
|
||||
/**
|
||||
* Perform inflation from XML and apply a class-specific base style from a
|
||||
* theme attribute or style resource. This constructor of Transition allows
|
||||
* subclasses to use their own base style when they are inflating.
|
||||
*
|
||||
* @param context The Context the transition is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param attrs The attributes of the XML tag that is inflating the transition.
|
||||
*/
|
||||
public Transition(Context context, AttributeSet attrs) {
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Transition);
|
||||
long duration = a.getInt(R.styleable.Transition_duration, -1);
|
||||
if (duration >= 0) {
|
||||
setDuration(duration);
|
||||
}
|
||||
long startDelay = a.getInt(R.styleable.Transition_startDelay, -1);
|
||||
if (startDelay > 0) {
|
||||
setStartDelay(startDelay);
|
||||
}
|
||||
final int resID = a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
|
||||
if (resID > 0) {
|
||||
setInterpolator(AnimationUtils.loadInterpolator(context, resID));
|
||||
}
|
||||
String matchOrder = a.getString(R.styleable.Transition_matchOrder);
|
||||
if (matchOrder != null) {
|
||||
setMatchOrder(parseMatchOrder(matchOrder));
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
private static int[] parseMatchOrder(String matchOrderString) {
|
||||
StringTokenizer st = new StringTokenizer(matchOrderString, ",");
|
||||
int matches[] = new int[st.countTokens()];
|
||||
int index = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken().trim();
|
||||
if (MATCH_ID_STR.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_ID;
|
||||
} else if (MATCH_INSTANCE_STR.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_INSTANCE;
|
||||
} else if (MATCH_NAME_STR.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_NAME;
|
||||
} else if (MATCH_VIEW_NAME_STR.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_NAME;
|
||||
} else if (MATCH_ITEM_ID_STR.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_ITEM_ID;
|
||||
} else if (token.isEmpty()) {
|
||||
int[] smallerMatches = new int[matches.length - 1];
|
||||
System.arraycopy(matches, 0, smallerMatches, 0, index);
|
||||
matches = smallerMatches;
|
||||
index--;
|
||||
} else {
|
||||
throw new InflateException("Unknown match type in matchOrder: '" + token + "'");
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration of this transition. By default, there is no duration
|
||||
* (indicated by a negative number), which means that the Animator created by
|
||||
@@ -1839,6 +1929,36 @@ public abstract class Transition implements Cloneable {
|
||||
return mEpicenterCallback.onGetEpicenter(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the algorithm used to calculate two-dimensional interpolation.
|
||||
* <p>
|
||||
* Transitions such as {@link android.transition.ChangeBounds} move Views, typically
|
||||
* in a straight path between the start and end positions. Applications that desire to
|
||||
* have these motions move in a curve can change how Views interpolate in two dimensions
|
||||
* by extending PathMotion and implementing
|
||||
* {@link android.transition.PathMotion#getPath(float, float, float, float)}.
|
||||
* </p>
|
||||
* @param pathMotion Algorithm object to use for determining how to interpolate in two
|
||||
* dimensions. If null, a straight-path algorithm will be used.
|
||||
*/
|
||||
public void setPathMotion(PathMotion pathMotion) {
|
||||
if (pathMotion == null) {
|
||||
mPathMotion = STRAIGHT_PATH_MOTION;
|
||||
} else {
|
||||
mPathMotion = pathMotion;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm object used to interpolate along two dimensions. This is typically
|
||||
* used to determine the View motion between two points.
|
||||
*
|
||||
* @return The algorithm object used to interpolate along two dimensions.
|
||||
*/
|
||||
public PathMotion getPathMotion() {
|
||||
return mPathMotion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the method for determining Animator start delays.
|
||||
* When a Transition affects several Views like {@link android.transition.Explode} or
|
||||
|
||||
@@ -16,21 +16,24 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Xml;
|
||||
import android.view.Gravity;
|
||||
import android.view.InflateException;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* This class inflates scenes and transitions from resource files.
|
||||
@@ -41,12 +44,11 @@ import java.util.StringTokenizer;
|
||||
* and {@link android.R.styleable#TransitionManager}.
|
||||
*/
|
||||
public class TransitionInflater {
|
||||
private static final String MATCH_INSTANCE = "instance";
|
||||
private static final String MATCH_NAME = "name";
|
||||
/** To be removed before L release */
|
||||
private static final String MATCH_VIEW_NAME = "viewName";
|
||||
private static final String MATCH_ID = "id";
|
||||
private static final String MATCH_ITEM_ID = "itemId";
|
||||
|
||||
private static final Class<?>[] sConstructorSignature = new Class[] {
|
||||
Context.class, AttributeSet.class};
|
||||
private final static ArrayMap<String, Constructor> sConstructors =
|
||||
new ArrayMap<String, Constructor>();
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@@ -118,9 +120,8 @@ public class TransitionInflater {
|
||||
//
|
||||
// Transition loading
|
||||
//
|
||||
|
||||
private Transition createTransitionFromXml(XmlPullParser parser,
|
||||
AttributeSet attrs, TransitionSet transitionSet)
|
||||
AttributeSet attrs, Transition parent)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
Transition transition = null;
|
||||
@@ -129,117 +130,105 @@ public class TransitionInflater {
|
||||
int type;
|
||||
int depth = parser.getDepth();
|
||||
|
||||
TransitionSet transitionSet = (parent instanceof TransitionSet)
|
||||
? (TransitionSet) parent : null;
|
||||
|
||||
while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
|
||||
&& type != XmlPullParser.END_DOCUMENT) {
|
||||
|
||||
boolean newTransition = false;
|
||||
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = parser.getName();
|
||||
if ("fade".equals(name)) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.Fade);
|
||||
int fadingMode = a.getInt(com.android.internal.R.styleable.Fade_fadingMode,
|
||||
Fade.IN | Fade.OUT);
|
||||
transition = new Fade(fadingMode);
|
||||
newTransition = true;
|
||||
transition = new Fade(mContext, attrs);
|
||||
} else if ("changeBounds".equals(name)) {
|
||||
transition = new ChangeBounds();
|
||||
newTransition = true;
|
||||
transition = new ChangeBounds(mContext, attrs);
|
||||
} else if ("slide".equals(name)) {
|
||||
transition = createSlideTransition(attrs);
|
||||
newTransition = true;
|
||||
transition = new Slide(mContext, attrs);
|
||||
} else if ("explode".equals(name)) {
|
||||
transition = new Explode();
|
||||
newTransition = true;
|
||||
transition = new Explode(mContext, attrs);
|
||||
} else if ("moveImage".equals(name)) {
|
||||
transition = new MoveImage();
|
||||
newTransition = true;
|
||||
transition = new MoveImage(mContext, attrs);
|
||||
} else if ("changeImageTransform".equals(name)) {
|
||||
transition = new ChangeImageTransform();
|
||||
newTransition = true;
|
||||
transition = new ChangeImageTransform(mContext, attrs);
|
||||
} else if ("changeTransform".equals(name)) {
|
||||
transition = new ChangeTransform();
|
||||
newTransition = true;
|
||||
transition = new ChangeTransform(mContext, attrs);
|
||||
} else if ("changeClipBounds".equals(name)) {
|
||||
transition = new ChangeClipBounds();
|
||||
newTransition = true;
|
||||
transition = new ChangeClipBounds(mContext, attrs);
|
||||
} else if ("autoTransition".equals(name)) {
|
||||
transition = new AutoTransition();
|
||||
newTransition = true;
|
||||
transition = new AutoTransition(mContext, attrs);
|
||||
} else if ("recolor".equals(name)) {
|
||||
transition = new Recolor();
|
||||
newTransition = true;
|
||||
transition = new Recolor(mContext, attrs);
|
||||
} else if ("transitionSet".equals(name)) {
|
||||
transition = new TransitionSet();
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.TransitionSet);
|
||||
int ordering = a.getInt(
|
||||
com.android.internal.R.styleable.TransitionSet_transitionOrdering,
|
||||
TransitionSet.ORDERING_TOGETHER);
|
||||
((TransitionSet) transition).setOrdering(ordering);
|
||||
createTransitionFromXml(parser, attrs, ((TransitionSet) transition));
|
||||
a.recycle();
|
||||
newTransition = true;
|
||||
transition = new TransitionSet(mContext, attrs);
|
||||
} else if ("transition".equals(name)) {
|
||||
transition = createCustomTransition(attrs);
|
||||
transition = (Transition) createCustom(attrs, Transition.class, "transition");
|
||||
} else if ("targets".equals(name)) {
|
||||
if (parser.getDepth() - 1 > depth && transition != null) {
|
||||
// We're inside the child tag - add targets to the child
|
||||
getTargetIds(parser, attrs, transition);
|
||||
} else if (parser.getDepth() - 1 == depth && transitionSet != null) {
|
||||
// add targets to the set
|
||||
getTargetIds(parser, attrs, transitionSet);
|
||||
}
|
||||
}
|
||||
if (transition != null || "targets".equals(name)) {
|
||||
if (newTransition) {
|
||||
loadTransition(transition, attrs);
|
||||
if (transitionSet != null) {
|
||||
transitionSet.addTransition(transition);
|
||||
}
|
||||
}
|
||||
getTargetIds(parser, attrs, parent);
|
||||
} else if ("arcMotion".equals(name)) {
|
||||
parent.setPathMotion(new ArcMotion(mContext, attrs));
|
||||
} else if ("pathMotion".equals(name)) {
|
||||
parent.setPathMotion((PathMotion)createCustom(attrs, PathMotion.class, "pathMotion"));
|
||||
} else if ("patternMotion".equals(name)) {
|
||||
parent.setPathMotion(new PatternMotion(mContext, attrs));
|
||||
} else {
|
||||
throw new RuntimeException("Unknown scene name: " + parser.getName());
|
||||
}
|
||||
if (transition != null) {
|
||||
if (!parser.isEmptyElementTag()) {
|
||||
createTransitionFromXml(parser, attrs, transition);
|
||||
}
|
||||
if (transitionSet != null) {
|
||||
transitionSet.addTransition(transition);
|
||||
transition = null;
|
||||
} else if (parent != null) {
|
||||
throw new InflateException("Could not add transition to another transition.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return transition;
|
||||
}
|
||||
|
||||
private Transition createCustomTransition(AttributeSet attrs) {
|
||||
private Object createCustom(AttributeSet attrs, Class expectedType, String tag) {
|
||||
String className = attrs.getAttributeValue(null, "class");
|
||||
|
||||
if (className == null) {
|
||||
throw new RuntimeException("transition tag must have a 'class' attribute");
|
||||
throw new InflateException(tag + " tag must have a 'class' attribute");
|
||||
}
|
||||
|
||||
try {
|
||||
Class c = Class.forName(className);
|
||||
if (!Transition.class.isAssignableFrom(c)) {
|
||||
throw new RuntimeException("transition class must be a Transition: " + className);
|
||||
}
|
||||
return (Transition) c.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException("Could not instantiate transition class", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Could not access default constructor for transition class "
|
||||
+ className, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Could not find transition class " + className, e);
|
||||
}
|
||||
}
|
||||
synchronized (sConstructors) {
|
||||
Constructor constructor = sConstructors.get(className);
|
||||
if (constructor == null) {
|
||||
Class c = mContext.getClassLoader().loadClass(className)
|
||||
.asSubclass(expectedType);
|
||||
if (c != null) {
|
||||
constructor = c.getConstructor(sConstructorSignature);
|
||||
sConstructors.put(className, constructor);
|
||||
}
|
||||
}
|
||||
|
||||
private Slide createSlideTransition(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.Slide);
|
||||
int edge = a.getInt(com.android.internal.R.styleable.Slide_slideEdge, Gravity.BOTTOM);
|
||||
Slide slide = new Slide(edge);
|
||||
a.recycle();
|
||||
return slide;
|
||||
return constructor.newInstance(mContext, attrs);
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
throw new InflateException("Could not instantiate " + expectedType + " class " +
|
||||
className, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new InflateException("Could not instantiate " + expectedType + " class " +
|
||||
className, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new InflateException("Could not instantiate " + expectedType + " class " +
|
||||
className, e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new InflateException("Could not instantiate " + expectedType + " class " +
|
||||
className, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new InflateException("Could not instantiate " + expectedType + " class " +
|
||||
className, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void getTargetIds(XmlPullParser parser,
|
||||
@@ -258,34 +247,27 @@ public class TransitionInflater {
|
||||
|
||||
String name = parser.getName();
|
||||
if (name.equals("target")) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.TransitionTarget);
|
||||
int id = a.getResourceId(
|
||||
com.android.internal.R.styleable.TransitionTarget_targetId, -1);
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TransitionTarget);
|
||||
int id = a.getResourceId(R.styleable.TransitionTarget_targetId, 0);
|
||||
String transitionName;
|
||||
if (id >= 0) {
|
||||
if (id != 0) {
|
||||
transition.addTarget(id);
|
||||
} else if ((id = a.getResourceId(
|
||||
com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
|
||||
} else if ((id = a.getResourceId(R.styleable.TransitionTarget_excludeId, 0)) != 0) {
|
||||
transition.excludeTarget(id, true);
|
||||
} else if ((transitionName = a.getString(
|
||||
com.android.internal.R.styleable.TransitionTarget_targetName))
|
||||
} else if ((transitionName = a.getString(R.styleable.TransitionTarget_targetName))
|
||||
!= null) {
|
||||
transition.addTarget(transitionName);
|
||||
} else if ((transitionName = a.getString(
|
||||
com.android.internal.R.styleable.TransitionTarget_excludeName))
|
||||
} else if ((transitionName = a.getString(R.styleable.TransitionTarget_excludeName))
|
||||
!= null) {
|
||||
transition.excludeTarget(transitionName, true);
|
||||
} else {
|
||||
String className = a.getString(
|
||||
com.android.internal.R.styleable.TransitionTarget_excludeClass);
|
||||
String className = a.getString(R.styleable.TransitionTarget_excludeClass);
|
||||
try {
|
||||
if (className != null) {
|
||||
Class clazz = Class.forName(className);
|
||||
transition.excludeTarget(clazz, true);
|
||||
} else if ((className = a.getString(
|
||||
com.android.internal.R.styleable.TransitionTarget_targetClass))
|
||||
!= null) {
|
||||
} else if ((className =
|
||||
a.getString(R.styleable.TransitionTarget_targetClass)) != null) {
|
||||
Class clazz = Class.forName(className);
|
||||
transition.addTarget(clazz);
|
||||
}
|
||||
@@ -299,72 +281,6 @@ public class TransitionInflater {
|
||||
}
|
||||
}
|
||||
|
||||
private int[] parseMatchOrder(String matchOrderString) {
|
||||
StringTokenizer st = new StringTokenizer(matchOrderString, ",");
|
||||
int matches[] = new int[st.countTokens()];
|
||||
int index = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken().trim();
|
||||
if (MATCH_ID.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_ID;
|
||||
} else if (MATCH_INSTANCE.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_INSTANCE;
|
||||
} else if (MATCH_NAME.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_NAME;
|
||||
} else if (MATCH_VIEW_NAME.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_NAME;
|
||||
} else if (MATCH_ITEM_ID.equalsIgnoreCase(token)) {
|
||||
matches[index] = Transition.MATCH_ITEM_ID;
|
||||
} else if (token.isEmpty()) {
|
||||
int[] smallerMatches = new int[matches.length - 1];
|
||||
System.arraycopy(matches, 0, smallerMatches, 0, index);
|
||||
matches = smallerMatches;
|
||||
index--;
|
||||
} else {
|
||||
throw new RuntimeException("Unknown match type in matchOrder: '" + token + "'");
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private Transition loadTransition(Transition transition, AttributeSet attrs)
|
||||
throws Resources.NotFoundException {
|
||||
|
||||
TypedArray a =
|
||||
mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Transition);
|
||||
long duration = a.getInt(com.android.internal.R.styleable.Transition_duration, -1);
|
||||
if (duration >= 0) {
|
||||
transition.setDuration(duration);
|
||||
}
|
||||
long startDelay = a.getInt(com.android.internal.R.styleable.Transition_startDelay, -1);
|
||||
if (startDelay > 0) {
|
||||
transition.setStartDelay(startDelay);
|
||||
}
|
||||
final int resID =
|
||||
a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
|
||||
if (resID > 0) {
|
||||
transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
|
||||
}
|
||||
String matchOrder =
|
||||
a.getString(com.android.internal.R.styleable.Transition_matchOrder);
|
||||
if (matchOrder != null) {
|
||||
transition.setMatchOrder(parseMatchOrder(matchOrder));
|
||||
}
|
||||
a.recycle();
|
||||
if (transition instanceof Visibility) {
|
||||
a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.VisibilityTransition);
|
||||
int mode = a.getInt(
|
||||
com.android.internal.R.styleable.VisibilityTransition_visibilityMode, 0);
|
||||
a.recycle();
|
||||
if (mode != 0) {
|
||||
((Visibility)transition).setMode(mode);
|
||||
}
|
||||
}
|
||||
return transition;
|
||||
}
|
||||
|
||||
//
|
||||
// TransitionManager loading
|
||||
//
|
||||
@@ -399,15 +315,11 @@ public class TransitionInflater {
|
||||
private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
|
||||
TransitionManager transitionManager) throws Resources.NotFoundException {
|
||||
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.TransitionManager);
|
||||
int transitionId = a.getResourceId(
|
||||
com.android.internal.R.styleable.TransitionManager_transition, -1);
|
||||
int fromId = a.getResourceId(
|
||||
com.android.internal.R.styleable.TransitionManager_fromScene, -1);
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TransitionManager);
|
||||
int transitionId = a.getResourceId(R.styleable.TransitionManager_transition, -1);
|
||||
int fromId = a.getResourceId(R.styleable.TransitionManager_fromScene, -1);
|
||||
Scene fromScene = (fromId < 0) ? null: Scene.getSceneForLayout(sceneRoot, fromId, mContext);
|
||||
int toId = a.getResourceId(
|
||||
com.android.internal.R.styleable.TransitionManager_toScene, -1);
|
||||
int toId = a.getResourceId(R.styleable.TransitionManager_toScene, -1);
|
||||
Scene toScene = (toId < 0) ? null : Scene.getSceneForLayout(sceneRoot, toId, mContext);
|
||||
|
||||
if (transitionId >= 0) {
|
||||
|
||||
@@ -16,9 +16,13 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.graphics.Rect;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -77,6 +81,15 @@ public class TransitionSet extends Transition {
|
||||
public TransitionSet() {
|
||||
}
|
||||
|
||||
public TransitionSet(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TransitionSet);
|
||||
int ordering = a.getInt(R.styleable.TransitionSet_transitionOrdering,
|
||||
TransitionSet.ORDERING_TOGETHER);
|
||||
setOrdering(ordering);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the play order of this set's child transitions.
|
||||
*
|
||||
@@ -272,6 +285,14 @@ public class TransitionSet extends Transition {
|
||||
return (TransitionSet) super.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPathMotion(PathMotion pathMotion) {
|
||||
super.setPathMotion(pathMotion);
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).setPathMotion(pathMotion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified child transition from this set.
|
||||
*
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
|
||||
package android.transition;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* This transition tracks changes to the visibility of target views in the
|
||||
* start and end scenes. Visibility is determined not just by the
|
||||
@@ -74,12 +78,25 @@ public abstract class Visibility extends Transition {
|
||||
|
||||
private int mMode = IN | OUT;
|
||||
|
||||
public Visibility() {}
|
||||
|
||||
public Visibility(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VisibilityTransition);
|
||||
int mode = a.getInt(R.styleable.VisibilityTransition_visibilityMode, 0);
|
||||
a.recycle();
|
||||
if (mode != 0) {
|
||||
setMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the transition to support appearing and/or disappearing Views, depending
|
||||
* on <code>mode</code>.
|
||||
*
|
||||
* @param mode The behavior supported by this transition, a combination of
|
||||
* {@link #IN} and {@link #OUT}.
|
||||
* @attr ref android.R.styleable#VisibilityTransition_visibilityMode
|
||||
*/
|
||||
public void setMode(int mode) {
|
||||
if ((mode & ~(IN | OUT)) != 0) {
|
||||
@@ -88,6 +105,17 @@ public abstract class Visibility extends Transition {
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether appearing and/or disappearing Views are supported.
|
||||
*
|
||||
* Returns whether appearing and/or disappearing Views are supported. A combination of
|
||||
* {@link #IN} and {@link #OUT}.
|
||||
* @attr ref android.R.styleable#VisibilityTransition_visibilityMode
|
||||
*/
|
||||
public int getMode() {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return sTransitionProperties;
|
||||
|
||||
@@ -5429,6 +5429,28 @@
|
||||
<attr name="toScene" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Use <code>arcMotion</code> as the root tag of the XML resource that
|
||||
describes a {@link android.transition.ArcMotion}. This must be used
|
||||
within a transition with which the PathMotion should be associated. -->
|
||||
<declare-styleable name="ArcMotion">
|
||||
<!-- The minimum arc angle in degrees between the start and end points when
|
||||
they are close to horizontal. -->
|
||||
<attr name="minimumHorizontalAngle" format="float" />
|
||||
<!-- The minimum arc angle in degrees between the start and end points when
|
||||
they are close to vertical. -->
|
||||
<attr name="minimumVerticalAngle" format="float" />
|
||||
<!-- The maximum arc angle in degrees between the start and end points. -->
|
||||
<attr name="maximumAngle" format="float" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Use <code>patternMotion</code> as the root tag of the XML resource that
|
||||
describes a {@link android.transition.PatternMotion}. This must be used
|
||||
within a transition with which the PathMotion should be associated. -->
|
||||
<declare-styleable name="PatternMotion">
|
||||
<!-- The path string describing the pattern to use for the PathMotion. -->
|
||||
<attr name="pathData" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- ========================== -->
|
||||
<!-- ValueAnimator class attributes -->
|
||||
<!-- ========================== -->
|
||||
|
||||
@@ -2216,6 +2216,9 @@
|
||||
<public type="attr" name="actionModeFindDrawable" />
|
||||
<public type="attr" name="actionModeWebSearchDrawable" />
|
||||
<public type="attr" name="visibilityMode" />
|
||||
<public type="attr" name="minimumHorizontalAngle" />
|
||||
<public type="attr" name="minimumVerticalAngle" />
|
||||
<public type="attr" name="maximumAngle" />
|
||||
|
||||
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user