Merge "Allow changing order of matching Views in Transitions."

This commit is contained in:
George Mount
2014-05-15 14:49:30 +00:00
committed by Android (Google) Code Review
5 changed files with 167 additions and 14 deletions

View File

@@ -796,6 +796,7 @@ package android {
field public static final int manageSpaceActivity = 16842756; // 0x1010004
field public static final int mapViewStyle = 16842890; // 0x101008a
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843861; // 0x1010455
field public static final int max = 16843062; // 0x1010136
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -29362,8 +29363,13 @@ package android.transition {
method public android.transition.Transition setDuration(long);
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 setPropagation(android.transition.TransitionPropagation);
method public android.transition.Transition setStartDelay(long);
field public static final int MATCH_ID = 3; // 0x3
field public static final int MATCH_INSTANCE = 1; // 0x1
field public static final int MATCH_ITEM_ID = 4; // 0x4
field public static final int MATCH_VIEW_NAME = 2; // 0x2
}
public static abstract class Transition.EpicenterCallback {

View File

@@ -24,7 +24,6 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -108,6 +107,40 @@ public abstract class Transition implements Cloneable {
private static final String LOG_TAG = "Transition";
static final boolean DBG = false;
/**
* With {@link #setMatchOrder(int...)}, chooses to match by View instance.
*/
public static final int MATCH_INSTANCE = 0x1;
private static final int MATCH_FIRST = MATCH_INSTANCE;
/**
* With {@link #setMatchOrder(int...)}, chooses to match by
* {@link android.view.View#getViewName()}. Null names will not be matched.
*/
public static final int MATCH_VIEW_NAME = 0x2;
/**
* With {@link #setMatchOrder(int...)}, chooses to match by
* {@link android.view.View#getId()}. Negative IDs will not be matched.
*/
public static final int MATCH_ID = 0x3;
/**
* With {@link #setMatchOrder(int...)}, chooses to match by the {@link android.widget.Adapter}
* item id. When {@link android.widget.Adapter#hasStableIds()} returns false, no match
* will be made for items.
*/
public static final int MATCH_ITEM_ID = 0x4;
private static final int MATCH_LAST = MATCH_ITEM_ID;
private static final int[] DEFAULT_MATCH_ORDER = {
MATCH_VIEW_NAME,
MATCH_INSTANCE,
MATCH_ID,
MATCH_ITEM_ID,
};
private String mName = getClass().getName();
long mStartDelay = -1;
@@ -127,6 +160,7 @@ public abstract class Transition implements Cloneable {
private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
TransitionSet mParent = null;
private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
// Per-animator information used for later canceling when future transitions overlap
private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
@@ -337,6 +371,53 @@ public abstract class Transition implements Cloneable {
return null;
}
/**
* Sets the order in which Transition matches View start and end values.
* <p>
* The default behavior is to match first by {@link android.view.View#getViewName()},
* then by View instance, then by {@link android.view.View#getId()} and finally
* by its item ID if it is in a direct child of ListView. The caller can
* choose to have only some or all of the values of {@link #MATCH_INSTANCE},
* {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
* the match algorithms supplied will be used to determine whether Views are the
* the same in both the start and end Scene. Views that do not match will be considered
* as entering or leaving the Scene.
* </p>
* @param matches A list of zero or more of {@link #MATCH_INSTANCE},
* {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
* If none are provided, then the default match order will be set.
*/
public void setMatchOrder(int... matches) {
if (matches == null || matches.length == 0) {
mMatchOrder = DEFAULT_MATCH_ORDER;
} else {
for (int i = 0; i < matches.length; i++) {
int match = matches[i];
if (!isValidMatch(match)) {
throw new IllegalArgumentException("matches contains invalid value");
}
if (alreadyContains(matches, i)) {
throw new IllegalArgumentException("matches contains a duplicate value");
}
}
mMatchOrder = matches.clone();
}
}
private static boolean isValidMatch(int match) {
return (match >= MATCH_FIRST && match <= MATCH_LAST);
}
private static boolean alreadyContains(int[] array, int searchIndex) {
int value = array[searchIndex];
for (int i = 0; i < searchIndex; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
/**
* Match start/end values by View instance. Adds matched values to startValuesList
* and endValuesList and removes them from unmatchedStart and unmatchedEnd.
@@ -464,6 +545,37 @@ public abstract class Transition implements Cloneable {
}
}
private void matchStartAndEnd(TransitionValuesMaps startValues,
TransitionValuesMaps endValues,
ArrayList<TransitionValues> startValuesList,
ArrayList<TransitionValues> endValuesList) {
ArrayMap<View, TransitionValues> unmatchedStart =
new ArrayMap<View, TransitionValues>(startValues.viewValues);
ArrayMap<View, TransitionValues> unmatchedEnd =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
for (int i = 0; i < mMatchOrder.length; i++) {
switch (mMatchOrder[i]) {
case MATCH_INSTANCE:
matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
break;
case MATCH_VIEW_NAME:
matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.nameValues, endValues.nameValues);
break;
case MATCH_ID:
matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.idValues, endValues.idValues);
break;
case MATCH_ITEM_ID:
matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.itemIdValues, endValues.itemIdValues);
break;
}
}
addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
}
/**
* This method, essentially a wrapper around all calls to createAnimator for all
* possible target views, is called with the entire set of start/end
@@ -480,21 +592,9 @@ public abstract class Transition implements Cloneable {
if (DBG) {
Log.d(LOG_TAG, "createAnimators() for " + this);
}
ArrayMap<View, TransitionValues> unmatchedStart =
new ArrayMap<View, TransitionValues>(startValues.viewValues);
ArrayMap<View, TransitionValues> unmatchedEnd =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.nameValues, endValues.nameValues);
matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.idValues, endValues.idValues);
matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
startValues.itemIdValues, endValues.itemIdValues);
addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
matchStartAndEnd(startValues, endValues, startValuesList, endValuesList);
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
long minStartDelay = Long.MAX_VALUE;

View File

@@ -30,6 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
* This class inflates scenes and transitions from resource files.
@@ -40,6 +41,10 @@ import java.util.ArrayList;
* and {@link android.R.styleable#TransitionManager}.
*/
public class TransitionInflater {
private static final String MATCH_INSTANCE = "instance";
private static final String MATCH_VIEW_NAME = "viewName";
private static final String MATCH_ID = "id";
private static final String MATCH_ITEM_ID = "itemId";
private Context mContext;
@@ -266,6 +271,33 @@ 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_VIEW_NAME.equalsIgnoreCase(token)) {
matches[index] = Transition.MATCH_VIEW_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 {
@@ -284,6 +316,11 @@ public class TransitionInflater {
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();
return transition;
}

View File

@@ -4989,6 +4989,15 @@
<attr name="startDelay" format="integer" />
<!-- Interpolator to be used in the animations spawned by this transition. -->
<attr name="interpolator" />
<!-- The match order to use for the transition. This is a comma-separated
list of values, containing one or more of the following:
id, itemId, viewName, instance. These correspond to
{@link android.transition.Transition#MATCH_ID},
{@link android.transition.Transition#MATCH_ITEM_ID},
{@link android.transition.Transition#MATCH_VIEW_NAME}, and
{@link android.transition.Transition#MATCH_INSTANCE}, respectively.
This corresponds to {@link android.transition.Transition#setMatchOrder(int...)}. -->
<attr name="matchOrder" format="string" />
</declare-styleable>
<!-- Use <code>fade</code>as the root tag of the XML resource that

View File

@@ -2170,6 +2170,7 @@
<public type="attr" name="splitTrack" />
<public type="attr" name="targetViewName" />
<public type="attr" name="excludeViewName" />
<public type="attr" name="matchOrder" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />