Merge changes Id7ae3838,I8e297443
* changes: Fix NPE when shared elements are empty. Allow antroid.transition Transitions in fragments.
This commit is contained in:
@@ -4203,6 +4203,9 @@ package android.app {
|
||||
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
|
||||
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
|
||||
method public abstract android.app.FragmentTransaction setCustomTransition(int, int);
|
||||
method public abstract android.app.FragmentTransaction setSharedElement(android.view.View, java.lang.String);
|
||||
method public abstract android.app.FragmentTransaction setSharedElements(android.util.Pair<android.view.View, java.lang.String>...);
|
||||
method public abstract android.app.FragmentTransaction setTransition(int);
|
||||
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
|
||||
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
|
||||
|
||||
@@ -293,13 +293,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
|
||||
if (transition == null || views == null || views.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// Add the targets to a set containing transition so that transition
|
||||
// remains unaffected. We don't want to modify the targets of transition itself.
|
||||
TransitionSet set = new TransitionSet();
|
||||
set.addTransition(transition);
|
||||
if (views != null) {
|
||||
for (View view: views) {
|
||||
for (View view : views) {
|
||||
set.addTarget(view);
|
||||
}
|
||||
}
|
||||
// By adding the transition after addTarget, we prevent addTarget from
|
||||
// affecting transition.
|
||||
set.addTransition(transition);
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,36 +16,53 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import com.android.internal.util.FastPrintWriter;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.transition.Transition;
|
||||
import android.transition.TransitionInflater;
|
||||
import android.transition.TransitionManager;
|
||||
import android.transition.TransitionSet;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LogWriter;
|
||||
import com.android.internal.util.FastPrintWriter;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
final class BackStackState implements Parcelable {
|
||||
final int[] mOps;
|
||||
final int mTransition;
|
||||
final int mTransitionStyle;
|
||||
final int mCustomTransition;
|
||||
final int mSceneRoot;
|
||||
final String mName;
|
||||
final int mIndex;
|
||||
final int mBreadCrumbTitleRes;
|
||||
final CharSequence mBreadCrumbTitleText;
|
||||
final int mBreadCrumbShortTitleRes;
|
||||
final CharSequence mBreadCrumbShortTitleText;
|
||||
final ArrayList<String> mSharedElementSourceNames;
|
||||
final ArrayList<String> mSharedElementTargetNames;
|
||||
|
||||
public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
|
||||
int numRemoved = 0;
|
||||
BackStackRecord.Op op = bse.mHead;
|
||||
while (op != null) {
|
||||
if (op.removed != null) numRemoved += op.removed.size();
|
||||
if (op.removed != null) {
|
||||
numRemoved += op.removed.size();
|
||||
}
|
||||
op = op.next;
|
||||
}
|
||||
mOps = new int[bse.mNumOp*7 + numRemoved];
|
||||
mOps = new int[bse.mNumOp * 7 + numRemoved];
|
||||
|
||||
if (!bse.mAddToBackStack) {
|
||||
throw new IllegalStateException("Not on back stack");
|
||||
@@ -63,7 +80,7 @@ final class BackStackState implements Parcelable {
|
||||
if (op.removed != null) {
|
||||
final int N = op.removed.size();
|
||||
mOps[pos++] = N;
|
||||
for (int i=0; i<N; i++) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
mOps[pos++] = op.removed.get(i).mIndex;
|
||||
}
|
||||
} else {
|
||||
@@ -79,6 +96,10 @@ final class BackStackState implements Parcelable {
|
||||
mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
|
||||
mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
|
||||
mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
|
||||
mCustomTransition = bse.mCustomTransition;
|
||||
mSceneRoot = bse.mSceneRoot;
|
||||
mSharedElementSourceNames = bse.mSharedElementSourceNames;
|
||||
mSharedElementTargetNames = bse.mSharedElementTargetNames;
|
||||
}
|
||||
|
||||
public BackStackState(Parcel in) {
|
||||
@@ -91,6 +112,10 @@ final class BackStackState implements Parcelable {
|
||||
mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
mBreadCrumbShortTitleRes = in.readInt();
|
||||
mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
mCustomTransition = in.readInt();
|
||||
mSceneRoot = in.readInt();
|
||||
mSharedElementSourceNames = in.createStringArrayList();
|
||||
mSharedElementTargetNames = in.createStringArrayList();
|
||||
}
|
||||
|
||||
public BackStackRecord instantiate(FragmentManagerImpl fm) {
|
||||
@@ -100,8 +125,10 @@ final class BackStackState implements Parcelable {
|
||||
while (pos < mOps.length) {
|
||||
BackStackRecord.Op op = new BackStackRecord.Op();
|
||||
op.cmd = mOps[pos++];
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
|
||||
"Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(FragmentManagerImpl.TAG,
|
||||
"Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
|
||||
}
|
||||
int findex = mOps[pos++];
|
||||
if (findex >= 0) {
|
||||
Fragment f = fm.mActive.get(findex);
|
||||
@@ -116,9 +143,11 @@ final class BackStackState implements Parcelable {
|
||||
final int N = mOps[pos++];
|
||||
if (N > 0) {
|
||||
op.removed = new ArrayList<Fragment>(N);
|
||||
for (int i=0; i<N; i++) {
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
|
||||
"Instantiate " + bse + " set remove fragment #" + mOps[pos]);
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(FragmentManagerImpl.TAG,
|
||||
"Instantiate " + bse + " set remove fragment #" + mOps[pos]);
|
||||
}
|
||||
Fragment r = fm.mActive.get(mOps[pos++]);
|
||||
op.removed.add(r);
|
||||
}
|
||||
@@ -135,6 +164,10 @@ final class BackStackState implements Parcelable {
|
||||
bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
|
||||
bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
|
||||
bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
|
||||
bse.mCustomTransition = mCustomTransition;
|
||||
bse.mSceneRoot = mSceneRoot;
|
||||
bse.mSharedElementSourceNames = mSharedElementSourceNames;
|
||||
bse.mSharedElementTargetNames = mSharedElementTargetNames;
|
||||
bse.bumpBackStackNesting(1);
|
||||
return bse;
|
||||
}
|
||||
@@ -153,6 +186,10 @@ final class BackStackState implements Parcelable {
|
||||
TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
|
||||
dest.writeInt(mBreadCrumbShortTitleRes);
|
||||
TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
|
||||
dest.writeInt(mCustomTransition);
|
||||
dest.writeInt(mSceneRoot);
|
||||
dest.writeStringList(mSharedElementSourceNames);
|
||||
dest.writeStringList(mSharedElementTargetNames);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<BackStackState> CREATOR
|
||||
@@ -217,6 +254,11 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
int mBreadCrumbShortTitleRes;
|
||||
CharSequence mBreadCrumbShortTitleText;
|
||||
|
||||
int mCustomTransition;
|
||||
int mSceneRoot;
|
||||
ArrayList<String> mSharedElementSourceNames;
|
||||
ArrayList<String> mSharedElementTargetNames;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
@@ -240,78 +282,112 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
|
||||
void dump(String prefix, PrintWriter writer, boolean full) {
|
||||
if (full) {
|
||||
writer.print(prefix); writer.print("mName="); writer.print(mName);
|
||||
writer.print(" mIndex="); writer.print(mIndex);
|
||||
writer.print(" mCommitted="); writer.println(mCommitted);
|
||||
writer.print(prefix);
|
||||
writer.print("mName=");
|
||||
writer.print(mName);
|
||||
writer.print(" mIndex=");
|
||||
writer.print(mIndex);
|
||||
writer.print(" mCommitted=");
|
||||
writer.println(mCommitted);
|
||||
if (mTransition != FragmentTransaction.TRANSIT_NONE) {
|
||||
writer.print(prefix); writer.print("mTransition=#");
|
||||
writer.print(Integer.toHexString(mTransition));
|
||||
writer.print(" mTransitionStyle=#");
|
||||
writer.println(Integer.toHexString(mTransitionStyle));
|
||||
writer.print(prefix);
|
||||
writer.print("mTransition=#");
|
||||
writer.print(Integer.toHexString(mTransition));
|
||||
writer.print(" mTransitionStyle=#");
|
||||
writer.println(Integer.toHexString(mTransitionStyle));
|
||||
}
|
||||
if (mEnterAnim != 0 || mExitAnim !=0) {
|
||||
writer.print(prefix); writer.print("mEnterAnim=#");
|
||||
writer.print(Integer.toHexString(mEnterAnim));
|
||||
writer.print(" mExitAnim=#");
|
||||
writer.println(Integer.toHexString(mExitAnim));
|
||||
if (mEnterAnim != 0 || mExitAnim != 0) {
|
||||
writer.print(prefix);
|
||||
writer.print("mEnterAnim=#");
|
||||
writer.print(Integer.toHexString(mEnterAnim));
|
||||
writer.print(" mExitAnim=#");
|
||||
writer.println(Integer.toHexString(mExitAnim));
|
||||
}
|
||||
if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
|
||||
writer.print(prefix); writer.print("mPopEnterAnim=#");
|
||||
writer.print(Integer.toHexString(mPopEnterAnim));
|
||||
writer.print(" mPopExitAnim=#");
|
||||
writer.println(Integer.toHexString(mPopExitAnim));
|
||||
if (mPopEnterAnim != 0 || mPopExitAnim != 0) {
|
||||
writer.print(prefix);
|
||||
writer.print("mPopEnterAnim=#");
|
||||
writer.print(Integer.toHexString(mPopEnterAnim));
|
||||
writer.print(" mPopExitAnim=#");
|
||||
writer.println(Integer.toHexString(mPopExitAnim));
|
||||
}
|
||||
if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
|
||||
writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
|
||||
writer.print(Integer.toHexString(mBreadCrumbTitleRes));
|
||||
writer.print(" mBreadCrumbTitleText=");
|
||||
writer.println(mBreadCrumbTitleText);
|
||||
writer.print(prefix);
|
||||
writer.print("mBreadCrumbTitleRes=#");
|
||||
writer.print(Integer.toHexString(mBreadCrumbTitleRes));
|
||||
writer.print(" mBreadCrumbTitleText=");
|
||||
writer.println(mBreadCrumbTitleText);
|
||||
}
|
||||
if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
|
||||
writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
|
||||
writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
|
||||
writer.print(" mBreadCrumbShortTitleText=");
|
||||
writer.println(mBreadCrumbShortTitleText);
|
||||
writer.print(prefix);
|
||||
writer.print("mBreadCrumbShortTitleRes=#");
|
||||
writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
|
||||
writer.print(" mBreadCrumbShortTitleText=");
|
||||
writer.println(mBreadCrumbShortTitleText);
|
||||
}
|
||||
}
|
||||
|
||||
if (mHead != null) {
|
||||
writer.print(prefix); writer.println("Operations:");
|
||||
writer.print(prefix);
|
||||
writer.println("Operations:");
|
||||
String innerPrefix = prefix + " ";
|
||||
Op op = mHead;
|
||||
int num = 0;
|
||||
while (op != null) {
|
||||
String cmdStr;
|
||||
switch (op.cmd) {
|
||||
case OP_NULL: cmdStr="NULL"; break;
|
||||
case OP_ADD: cmdStr="ADD"; break;
|
||||
case OP_REPLACE: cmdStr="REPLACE"; break;
|
||||
case OP_REMOVE: cmdStr="REMOVE"; break;
|
||||
case OP_HIDE: cmdStr="HIDE"; break;
|
||||
case OP_SHOW: cmdStr="SHOW"; break;
|
||||
case OP_DETACH: cmdStr="DETACH"; break;
|
||||
case OP_ATTACH: cmdStr="ATTACH"; break;
|
||||
default: cmdStr="cmd=" + op.cmd; break;
|
||||
case OP_NULL:
|
||||
cmdStr = "NULL";
|
||||
break;
|
||||
case OP_ADD:
|
||||
cmdStr = "ADD";
|
||||
break;
|
||||
case OP_REPLACE:
|
||||
cmdStr = "REPLACE";
|
||||
break;
|
||||
case OP_REMOVE:
|
||||
cmdStr = "REMOVE";
|
||||
break;
|
||||
case OP_HIDE:
|
||||
cmdStr = "HIDE";
|
||||
break;
|
||||
case OP_SHOW:
|
||||
cmdStr = "SHOW";
|
||||
break;
|
||||
case OP_DETACH:
|
||||
cmdStr = "DETACH";
|
||||
break;
|
||||
case OP_ATTACH:
|
||||
cmdStr = "ATTACH";
|
||||
break;
|
||||
default:
|
||||
cmdStr = "cmd=" + op.cmd;
|
||||
break;
|
||||
}
|
||||
writer.print(prefix); writer.print(" Op #"); writer.print(num);
|
||||
writer.print(": "); writer.print(cmdStr);
|
||||
writer.print(" "); writer.println(op.fragment);
|
||||
writer.print(prefix);
|
||||
writer.print(" Op #");
|
||||
writer.print(num);
|
||||
writer.print(": ");
|
||||
writer.print(cmdStr);
|
||||
writer.print(" ");
|
||||
writer.println(op.fragment);
|
||||
if (full) {
|
||||
if (op.enterAnim != 0 || op.exitAnim != 0) {
|
||||
writer.print(innerPrefix); writer.print("enterAnim=#");
|
||||
writer.print(Integer.toHexString(op.enterAnim));
|
||||
writer.print(" exitAnim=#");
|
||||
writer.println(Integer.toHexString(op.exitAnim));
|
||||
writer.print(innerPrefix);
|
||||
writer.print("enterAnim=#");
|
||||
writer.print(Integer.toHexString(op.enterAnim));
|
||||
writer.print(" exitAnim=#");
|
||||
writer.println(Integer.toHexString(op.exitAnim));
|
||||
}
|
||||
if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
|
||||
writer.print(innerPrefix); writer.print("popEnterAnim=#");
|
||||
writer.print(Integer.toHexString(op.popEnterAnim));
|
||||
writer.print(" popExitAnim=#");
|
||||
writer.println(Integer.toHexString(op.popExitAnim));
|
||||
writer.print(innerPrefix);
|
||||
writer.print("popEnterAnim=#");
|
||||
writer.print(Integer.toHexString(op.popEnterAnim));
|
||||
writer.print(" popExitAnim=#");
|
||||
writer.println(Integer.toHexString(op.popExitAnim));
|
||||
}
|
||||
}
|
||||
if (op.removed != null && op.removed.size() > 0) {
|
||||
for (int i=0; i<op.removed.size(); i++) {
|
||||
for (int i = 0; i < op.removed.size(); i++) {
|
||||
writer.print(innerPrefix);
|
||||
if (op.removed.size() == 1) {
|
||||
writer.print("Removed: ");
|
||||
@@ -319,8 +395,10 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
if (i == 0) {
|
||||
writer.println("Removed:");
|
||||
}
|
||||
writer.print(innerPrefix); writer.print(" #"); writer.print(i);
|
||||
writer.print(": ");
|
||||
writer.print(innerPrefix);
|
||||
writer.print(" #");
|
||||
writer.print(i);
|
||||
writer.print(": ");
|
||||
}
|
||||
writer.println(op.removed.get(i));
|
||||
}
|
||||
@@ -494,6 +572,51 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
|
||||
mSceneRoot = sceneRootId;
|
||||
mCustomTransition = transitionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentTransaction setSharedElement(View sharedElement, String name) {
|
||||
String viewName = sharedElement.getViewName();
|
||||
if (viewName == null) {
|
||||
throw new IllegalArgumentException("Unique viewNames are required for all" +
|
||||
" sharedElements");
|
||||
}
|
||||
mSharedElementSourceNames = new ArrayList<String>(1);
|
||||
mSharedElementSourceNames.add(viewName);
|
||||
|
||||
mSharedElementTargetNames = new ArrayList<String>(1);
|
||||
mSharedElementTargetNames.add(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FragmentTransaction setSharedElements(Pair<View, String>... sharedElements) {
|
||||
if (sharedElements == null || sharedElements.length == 0) {
|
||||
mSharedElementSourceNames = null;
|
||||
mSharedElementTargetNames = null;
|
||||
} else {
|
||||
ArrayList<String> sourceNames = new ArrayList<String>(sharedElements.length);
|
||||
ArrayList<String> targetNames = new ArrayList<String>(sharedElements.length);
|
||||
for (int i = 0; i < sharedElements.length; i++) {
|
||||
String viewName = sharedElements[i].first.getViewName();
|
||||
if (viewName == null) {
|
||||
throw new IllegalArgumentException("Unique viewNames are required for all" +
|
||||
" sharedElements");
|
||||
}
|
||||
sourceNames.add(viewName);
|
||||
targetNames.add(sharedElements[i].second);
|
||||
}
|
||||
mSharedElementSourceNames = sourceNames;
|
||||
mSharedElementTargetNames = targetNames;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentTransaction setTransitionStyle(int styleRes) {
|
||||
mTransitionStyle = styleRes;
|
||||
return this;
|
||||
@@ -550,21 +673,27 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
if (!mAddToBackStack) {
|
||||
return;
|
||||
}
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this
|
||||
+ " by " + amt);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Bump nesting in " + this
|
||||
+ " by " + amt);
|
||||
}
|
||||
Op op = mHead;
|
||||
while (op != null) {
|
||||
if (op.fragment != null) {
|
||||
op.fragment.mBackStackNesting += amt;
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
|
||||
+ op.fragment + " to " + op.fragment.mBackStackNesting);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Bump nesting of "
|
||||
+ op.fragment + " to " + op.fragment.mBackStackNesting);
|
||||
}
|
||||
}
|
||||
if (op.removed != null) {
|
||||
for (int i=op.removed.size()-1; i>=0; i--) {
|
||||
for (int i = op.removed.size() - 1; i >= 0; i--) {
|
||||
Fragment r = op.removed.get(i);
|
||||
r.mBackStackNesting += amt;
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
|
||||
+ r + " to " + r.mBackStackNesting);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Bump nesting of "
|
||||
+ r + " to " + r.mBackStackNesting);
|
||||
}
|
||||
}
|
||||
}
|
||||
op = op.next;
|
||||
@@ -578,9 +707,11 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
public int commitAllowingStateLoss() {
|
||||
return commitInternal(true);
|
||||
}
|
||||
|
||||
|
||||
int commitInternal(boolean allowStateLoss) {
|
||||
if (mCommitted) throw new IllegalStateException("commit already called");
|
||||
if (mCommitted) {
|
||||
throw new IllegalStateException("commit already called");
|
||||
}
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Commit: " + this);
|
||||
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
|
||||
@@ -597,9 +728,11 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
mManager.enqueueAction(this, allowStateLoss);
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Run: " + this);
|
||||
}
|
||||
|
||||
if (mAddToBackStack) {
|
||||
if (mIndex < 0) {
|
||||
@@ -609,6 +742,9 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
|
||||
bumpBackStackNesting(1);
|
||||
|
||||
TransitionState state = beginTransition(mSharedElementSourceNames,
|
||||
mSharedElementTargetNames);
|
||||
|
||||
Op op = mHead;
|
||||
while (op != null) {
|
||||
switch (op.cmd) {
|
||||
@@ -616,14 +752,17 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.enterAnim;
|
||||
mManager.addFragment(f, false);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_REPLACE: {
|
||||
Fragment f = op.fragment;
|
||||
if (mManager.mAdded != null) {
|
||||
for (int i=0; i<mManager.mAdded.size(); i++) {
|
||||
for (int i = 0; i < mManager.mAdded.size(); i++) {
|
||||
Fragment old = mManager.mAdded.get(i);
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG,
|
||||
"OP_REPLACE: adding=" + f + " old=" + old);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG,
|
||||
"OP_REPLACE: adding=" + f + " old=" + old);
|
||||
}
|
||||
if (f == null || old.mContainerId == f.mContainerId) {
|
||||
if (old == f) {
|
||||
op.fragment = f = null;
|
||||
@@ -635,8 +774,10 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
old.mNextAnim = op.exitAnim;
|
||||
if (mAddToBackStack) {
|
||||
old.mBackStackNesting += 1;
|
||||
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
|
||||
+ old + " to " + old.mBackStackNesting);
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "Bump nesting of "
|
||||
+ old + " to " + old.mBackStackNesting);
|
||||
}
|
||||
}
|
||||
mManager.removeFragment(old, mTransition, mTransitionStyle);
|
||||
}
|
||||
@@ -647,32 +788,38 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
f.mNextAnim = op.enterAnim;
|
||||
mManager.addFragment(f, false);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_REMOVE: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.exitAnim;
|
||||
mManager.removeFragment(f, mTransition, mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_HIDE: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.exitAnim;
|
||||
mManager.hideFragment(f, mTransition, mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_SHOW: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.enterAnim;
|
||||
mManager.showFragment(f, mTransition, mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_DETACH: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.exitAnim;
|
||||
mManager.detachFragment(f, mTransition, mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_ATTACH: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.enterAnim;
|
||||
mManager.attachFragment(f, mTransition, mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
|
||||
}
|
||||
@@ -687,9 +834,174 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
if (mAddToBackStack) {
|
||||
mManager.addBackStackState(this);
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
updateTransitionEndState(state, mSharedElementTargetNames);
|
||||
}
|
||||
}
|
||||
|
||||
public void popFromBackStack(boolean doStateMove) {
|
||||
private TransitionState beginTransition(ArrayList<String> sourceNames,
|
||||
ArrayList<String> targetNames) {
|
||||
if (mCustomTransition <= 0 || mSceneRoot <= 0) {
|
||||
return null;
|
||||
}
|
||||
View rootView = mManager.mContainer.findViewById(mSceneRoot);
|
||||
if (!(rootView instanceof ViewGroup)) {
|
||||
throw new IllegalArgumentException("SceneRoot is not a ViewGroup");
|
||||
}
|
||||
TransitionState state = new TransitionState();
|
||||
// get Transition scene root and create Transitions
|
||||
state.sceneRoot = (ViewGroup) rootView;
|
||||
state.sceneRoot.captureTransitioningViews(state.transitioningViews);
|
||||
|
||||
state.exitTransition = TransitionInflater.from(mManager.mActivity)
|
||||
.inflateTransition(mCustomTransition);
|
||||
state.sharedElementTransition = TransitionInflater.from(mManager.mActivity)
|
||||
.inflateTransition(mCustomTransition);
|
||||
state.enterTransition = TransitionInflater.from(mManager.mActivity)
|
||||
.inflateTransition(mCustomTransition);
|
||||
// Adding a non-existent target view makes sure that the transitions don't target
|
||||
// any views by default. They'll only target the views we tell add. If we don't
|
||||
// add any, then no views will be targeted.
|
||||
View nonExistentView = new View(mManager.mActivity);
|
||||
state.enterTransition.addTarget(nonExistentView);
|
||||
state.exitTransition.addTarget(nonExistentView);
|
||||
state.sharedElementTransition.addTarget(nonExistentView);
|
||||
|
||||
setSharedElementEpicenter(state.enterTransition, state);
|
||||
|
||||
state.excludingTransition = new TransitionSet()
|
||||
.addTransition(state.exitTransition)
|
||||
.addTransition(state.enterTransition);
|
||||
|
||||
if (sourceNames != null) {
|
||||
// Map shared elements.
|
||||
state.sceneRoot.findNamedViews(state.namedViews);
|
||||
state.namedViews.retainAll(sourceNames);
|
||||
View epicenterView = state.namedViews.get(sourceNames.get(0));
|
||||
if (epicenterView != null) {
|
||||
// The epicenter is only the first shared element.
|
||||
setEpicenter(state.exitTransition, epicenterView);
|
||||
setEpicenter(state.sharedElementTransition, epicenterView);
|
||||
}
|
||||
state.transitioningViews.removeAll(state.namedViews.values());
|
||||
state.excludingTransition.addTransition(state.sharedElementTransition);
|
||||
addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
|
||||
}
|
||||
|
||||
// Adds the (maybe) exiting views, not including the shared element.
|
||||
// If some stay, that's ok.
|
||||
addTransitioningViews(state.exitTransition, state.transitioningViews);
|
||||
|
||||
// Prepare for shared element name mapping. This could be chained in the case
|
||||
// of popping several back stack states.
|
||||
state.excludingTransition.setNameOverrides(new ArrayMap<String, String>());
|
||||
setNameOverrides(state, sourceNames, targetNames);
|
||||
|
||||
// Don't include any subtree in the views that are hidden when capturing the
|
||||
// view hierarchy transitions. They should be as if not there.
|
||||
excludeHiddenFragments(state, true);
|
||||
|
||||
TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition);
|
||||
return state;
|
||||
}
|
||||
|
||||
private void updateTransitionEndState(TransitionState state, ArrayList<String> names) {
|
||||
// Find all views that are entering.
|
||||
ArrayList<View> enteringViews = new ArrayList<View>();
|
||||
state.sceneRoot.captureTransitioningViews(enteringViews);
|
||||
enteringViews.removeAll(state.transitioningViews);
|
||||
|
||||
if (names != null) {
|
||||
// find all shared elements.
|
||||
state.namedViews.clear();
|
||||
state.sceneRoot.findNamedViews(state.namedViews);
|
||||
state.namedViews.retainAll(names);
|
||||
if (!state.namedViews.isEmpty()) {
|
||||
enteringViews.removeAll(state.namedViews.values());
|
||||
addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
|
||||
// now we know the epicenter of the entering transition.
|
||||
state.mEnteringEpicenterView = state.namedViews.get(names.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Add all entering views to the enter transition.
|
||||
addTransitioningViews(state.enterTransition, enteringViews);
|
||||
|
||||
// Don't allow capturing state for the newly-hidden fragments.
|
||||
excludeHiddenFragments(state, false);
|
||||
|
||||
// Allow capturing state for the newly-shown fragments
|
||||
includeVisibleFragments(state.excludingTransition);
|
||||
}
|
||||
|
||||
private void addTransitioningViews(Transition transition, Collection<View> views) {
|
||||
if (views.isEmpty()) {
|
||||
// Add a view so that we can modify the valid views at the end of the
|
||||
// fragment transaction.
|
||||
transition.addTarget(new View(mManager.mActivity));
|
||||
} else {
|
||||
for (View view : views) {
|
||||
transition.addTarget(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void excludeHiddenFragments(TransitionState state, boolean forceExclude) {
|
||||
if (mManager.mAdded != null) {
|
||||
for (int i = 0; i < mManager.mAdded.size(); i++) {
|
||||
Fragment fragment = mManager.mAdded.get(i);
|
||||
if (fragment.mView != null && fragment.mHidden
|
||||
&& (forceExclude || !state.hiddenViews.contains(fragment.mView))) {
|
||||
state.excludingTransition.excludeTarget(fragment.mView, true);
|
||||
state.hiddenViews.add(fragment.mView);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forceExclude && state.hiddenViews.isEmpty()) {
|
||||
state.excludingTransition.excludeTarget(new View(mManager.mActivity), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void includeVisibleFragments(Transition transition) {
|
||||
if (mManager.mAdded != null) {
|
||||
for (int i = 0; i < mManager.mAdded.size(); i++) {
|
||||
Fragment fragment = mManager.mAdded.get(i);
|
||||
if (fragment.mView != null && !fragment.mHidden) {
|
||||
transition.excludeTarget(fragment.mView, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setEpicenter(Transition transition, View view) {
|
||||
final Rect epicenter = new Rect();
|
||||
view.getBoundsOnScreen(epicenter);
|
||||
|
||||
transition.setEpicenterCallback(new Transition.EpicenterCallback() {
|
||||
@Override
|
||||
public Rect onGetEpicenter(Transition transition) {
|
||||
return epicenter;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setSharedElementEpicenter(Transition transition, final TransitionState state) {
|
||||
transition.setEpicenterCallback(new Transition.EpicenterCallback() {
|
||||
private Rect mEpicenter;
|
||||
|
||||
@Override
|
||||
public Rect onGetEpicenter(Transition transition) {
|
||||
if (mEpicenter == null && state.mEnteringEpicenterView != null) {
|
||||
mEpicenter = new Rect();
|
||||
state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter);
|
||||
}
|
||||
return mEpicenter;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) {
|
||||
if (FragmentManagerImpl.DEBUG) {
|
||||
Log.v(TAG, "popFromBackStack: " + this);
|
||||
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
|
||||
@@ -698,6 +1010,12 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
pw.flush();
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames);
|
||||
} else {
|
||||
setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
|
||||
}
|
||||
|
||||
bumpBackStackNesting(-1);
|
||||
|
||||
Op op = mTail;
|
||||
@@ -709,7 +1027,8 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
mManager.removeFragment(f,
|
||||
FragmentManagerImpl.reverseTransit(mTransition),
|
||||
mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_REPLACE: {
|
||||
Fragment f = op.fragment;
|
||||
if (f != null) {
|
||||
@@ -719,42 +1038,48 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
mTransitionStyle);
|
||||
}
|
||||
if (op.removed != null) {
|
||||
for (int i=0; i<op.removed.size(); i++) {
|
||||
for (int i = 0; i < op.removed.size(); i++) {
|
||||
Fragment old = op.removed.get(i);
|
||||
old.mNextAnim = op.popEnterAnim;
|
||||
mManager.addFragment(old, false);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_REMOVE: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.popEnterAnim;
|
||||
mManager.addFragment(f, false);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_HIDE: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.popEnterAnim;
|
||||
mManager.showFragment(f,
|
||||
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_SHOW: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.popExitAnim;
|
||||
mManager.hideFragment(f,
|
||||
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_DETACH: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.popEnterAnim;
|
||||
mManager.attachFragment(f,
|
||||
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case OP_ATTACH: {
|
||||
Fragment f = op.fragment;
|
||||
f.mNextAnim = op.popExitAnim;
|
||||
mManager.detachFragment(f,
|
||||
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
|
||||
}
|
||||
@@ -766,12 +1091,39 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
if (doStateMove) {
|
||||
mManager.moveToState(mManager.mCurState,
|
||||
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
|
||||
if (state != null) {
|
||||
updateTransitionEndState(state, mSharedElementSourceNames);
|
||||
state = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIndex >= 0) {
|
||||
mManager.freeBackStackIndex(mIndex);
|
||||
mIndex = -1;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
private static void setNameOverride(Transition transition, String source, String target) {
|
||||
ArrayMap<String, String> overrides = transition.getNameOverrides();
|
||||
for (int index = 0; index < overrides.size(); index++) {
|
||||
if (source.equals(overrides.valueAt(index))) {
|
||||
overrides.setValueAt(index, target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
overrides.put(source, target);
|
||||
}
|
||||
|
||||
private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames,
|
||||
ArrayList<String> targetNames) {
|
||||
if (sourceNames != null) {
|
||||
for (int i = 0; i < sourceNames.size(); i++) {
|
||||
String source = sourceNames.get(i);
|
||||
String target = targetNames.get(i);
|
||||
setNameOverride(state.excludingTransition, source, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -789,4 +1141,16 @@ final class BackStackRecord extends FragmentTransaction implements
|
||||
public boolean isEmpty() {
|
||||
return mNumOp == 0;
|
||||
}
|
||||
|
||||
public class TransitionState {
|
||||
public ArrayList<View> hiddenViews = new ArrayList<View>();
|
||||
public ArrayList<View> transitioningViews = new ArrayList<View>();
|
||||
public ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
|
||||
public Transition exitTransition;
|
||||
public Transition sharedElementTransition;
|
||||
public Transition enterTransition;
|
||||
public TransitionSet excludingTransition;
|
||||
public ViewGroup sceneRoot;
|
||||
public View mEnteringEpicenterView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,8 +133,10 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
|
||||
public void onTransitionEnd(Transition transition) {
|
||||
setViewVisibility(mSharedElements, View.INVISIBLE);
|
||||
ViewGroupOverlay overlay = getDecor().getOverlay();
|
||||
for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
|
||||
overlay.add(mSharedElementSnapshots.get(i));
|
||||
if (mSharedElementSnapshots != null) {
|
||||
for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
|
||||
overlay.add(mSharedElementSnapshots.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1494,7 +1494,7 @@ final class FragmentManagerImpl extends FragmentManager {
|
||||
return false;
|
||||
}
|
||||
final BackStackRecord bss = mBackStack.remove(last);
|
||||
bss.popFromBackStack(true);
|
||||
bss.popFromBackStack(true, null);
|
||||
reportBackStackChanged();
|
||||
} else {
|
||||
int index = -1;
|
||||
@@ -1538,9 +1538,10 @@ final class FragmentManagerImpl extends FragmentManager {
|
||||
states.add(mBackStack.remove(i));
|
||||
}
|
||||
final int LAST = states.size()-1;
|
||||
BackStackRecord.TransitionState state = null;
|
||||
for (int i=0; i<=LAST; i++) {
|
||||
if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
|
||||
states.get(i).popFromBackStack(i == LAST);
|
||||
state = states.get(i).popFromBackStack(i == LAST, state);
|
||||
}
|
||||
reportBackStackChanged();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package android.app;
|
||||
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* API for performing a set of Fragment operations.
|
||||
*
|
||||
@@ -168,6 +171,36 @@ public abstract class FragmentTransaction {
|
||||
*/
|
||||
public abstract FragmentTransaction setTransition(int transit);
|
||||
|
||||
/**
|
||||
* Set a {@link android.transition.Transition} resource id to use with this transaction.
|
||||
* <var>transitionId</var> will be played for fragments when going forward and when popping
|
||||
* the back stack.
|
||||
* @param sceneRootId The ID of the element acting as the scene root for the transition.
|
||||
* This should be a ViewGroup containing all Fragments in the transaction.
|
||||
* @param transitionId The resource ID for the Transition used during the Fragment transaction.
|
||||
*/
|
||||
public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId);
|
||||
|
||||
/**
|
||||
* Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
|
||||
* Fragment to a View from a shown or added Fragment.
|
||||
* <var>sharedElement</var> must have a unique viewName in the View hierarchy.
|
||||
* @param sharedElement A View in a disappearing Fragment to match with a View in an
|
||||
* appearing Fragment.
|
||||
* @param name The viewName for a View in an appearing Fragment to match to the shared
|
||||
* element.
|
||||
*/
|
||||
public abstract FragmentTransaction setSharedElement(View sharedElement, String name);
|
||||
|
||||
/**
|
||||
* Used with {@link #setCustomTransition(int, int)} to map multiple Views from removed or hidden
|
||||
* Fragments to a Views from a shown or added Fragments. Views in
|
||||
* <var>sharedElements</var> must have unique viewNames in the View hierarchy.
|
||||
* @param sharedElements Pairs of Views in disappearing Fragments to viewNames in
|
||||
* appearing Fragments.
|
||||
*/
|
||||
public abstract FragmentTransaction setSharedElements(Pair<View, String>... sharedElements);
|
||||
|
||||
/**
|
||||
* Set a custom style resource that will be used for resolving transit
|
||||
* animations.
|
||||
|
||||
@@ -206,6 +206,10 @@ public abstract class Transition implements Cloneable {
|
||||
// like CircularPropagation
|
||||
EpicenterCallback mEpicenterCallback;
|
||||
|
||||
// For Fragment shared element transitions, linking views explicitly by mismatching
|
||||
// viewNames.
|
||||
ArrayMap<String, String> mNameOverrides;
|
||||
|
||||
/**
|
||||
* Constructs a Transition object with no target objects. A transition with
|
||||
* no targets defaults to running on all target objects in the scene hierarchy
|
||||
@@ -1347,6 +1351,21 @@ public abstract class Transition implements Cloneable {
|
||||
} else {
|
||||
captureHierarchy(sceneRoot, start);
|
||||
}
|
||||
if (!start && mNameOverrides != null) {
|
||||
int numOverrides = mNameOverrides.size();
|
||||
ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
|
||||
for (int i = 0; i < numOverrides; i++) {
|
||||
String fromName = mNameOverrides.keyAt(i);
|
||||
overriddenViews.add(mStartValues.nameValues.remove(fromName));
|
||||
}
|
||||
for (int i = 0; i < numOverrides; i++) {
|
||||
View view = overriddenViews.get(i);
|
||||
if (view != null) {
|
||||
String toName = mNameOverrides.valueAt(i);
|
||||
mStartValues.nameValues.put(toName, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addViewValues(TransitionValuesMaps transitionValuesMaps,
|
||||
@@ -1400,10 +1419,12 @@ public abstract class Transition implements Cloneable {
|
||||
mStartValues.viewValues.clear();
|
||||
mStartValues.idValues.clear();
|
||||
mStartValues.itemIdValues.clear();
|
||||
mStartValues.nameValues.clear();
|
||||
} else {
|
||||
mEndValues.viewValues.clear();
|
||||
mEndValues.idValues.clear();
|
||||
mEndValues.itemIdValues.clear();
|
||||
mEndValues.nameValues.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1866,6 +1887,20 @@ public abstract class Transition implements Cloneable {
|
||||
return mCanRemoveViews;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shared element names -- a mapping from a name at the start state to
|
||||
* a different name at the end state.
|
||||
* @hide
|
||||
*/
|
||||
public void setNameOverrides(ArrayMap<String, String> overrides) {
|
||||
mNameOverrides = overrides;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public ArrayMap<String, String> getNameOverrides() {
|
||||
return mNameOverrides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString("");
|
||||
|
||||
@@ -168,14 +168,36 @@ public class TransitionSet extends Transition {
|
||||
|
||||
@Override
|
||||
public TransitionSet addTarget(View target) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).addTarget(target);
|
||||
}
|
||||
return (TransitionSet) super.addTarget(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet addTarget(int targetId) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).addTarget(targetId);
|
||||
}
|
||||
return (TransitionSet) super.addTarget(targetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet addTarget(String targetName) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).addTarget(targetName);
|
||||
}
|
||||
return (TransitionSet) super.addTarget(targetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet addTarget(Class targetType) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).addTarget(targetType);
|
||||
}
|
||||
return (TransitionSet) super.addTarget(targetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet addListener(TransitionListener listener) {
|
||||
return (TransitionSet) super.addListener(listener);
|
||||
@@ -183,14 +205,68 @@ public class TransitionSet extends Transition {
|
||||
|
||||
@Override
|
||||
public TransitionSet removeTarget(int targetId) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).removeTarget(targetId);
|
||||
}
|
||||
return (TransitionSet) super.removeTarget(targetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet removeTarget(View target) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).removeTarget(target);
|
||||
}
|
||||
return (TransitionSet) super.removeTarget(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet removeTarget(Class target) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).removeTarget(target);
|
||||
}
|
||||
return (TransitionSet) super.removeTarget(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet removeTarget(String target) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).removeTarget(target);
|
||||
}
|
||||
return (TransitionSet) super.removeTarget(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transition excludeTarget(View target, boolean exclude) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).excludeTarget(target, exclude);
|
||||
}
|
||||
return super.excludeTarget(target, exclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transition excludeTarget(String targetViewName, boolean exclude) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).excludeTarget(targetViewName, exclude);
|
||||
}
|
||||
return super.excludeTarget(targetViewName, exclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transition excludeTarget(int targetId, boolean exclude) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).excludeTarget(targetId, exclude);
|
||||
}
|
||||
return super.excludeTarget(targetId, exclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transition excludeTarget(Class type, boolean exclude) {
|
||||
for (int i = 0; i < mTransitions.size(); i++) {
|
||||
mTransitions.get(i).excludeTarget(type, exclude);
|
||||
}
|
||||
return super.excludeTarget(type, exclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransitionSet removeListener(TransitionListener listener) {
|
||||
return (TransitionSet) super.removeListener(listener);
|
||||
|
||||
@@ -18,6 +18,9 @@ package android.transition;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -272,15 +275,23 @@ public abstract class Visibility extends Transition {
|
||||
if (startView.getParent() == null) {
|
||||
// no parent - safe to use
|
||||
overlayView = startView;
|
||||
} else if (startView.getParent() instanceof View &&
|
||||
startView.getParent().getParent() == null) {
|
||||
} else if (startView.getParent() instanceof View) {
|
||||
View startParent = (View) startView.getParent();
|
||||
int id = startParent.getId();
|
||||
if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) {
|
||||
// no parent, but its parent is unparented but the parent
|
||||
// hierarchy has been replaced by a new hierarchy with the same id
|
||||
// and it is safe to un-parent startView
|
||||
overlayView = startView;
|
||||
if (!isValidTarget(startParent)) {
|
||||
if (startView.isAttachedToWindow()) {
|
||||
overlayView = copyViewImage(startView);
|
||||
} else {
|
||||
overlayView = startView;
|
||||
}
|
||||
} else if (startParent.getParent() == null) {
|
||||
int id = startParent.getId();
|
||||
if (id != View.NO_ID && sceneRoot.findViewById(id) != null
|
||||
&& mCanRemoveViews) {
|
||||
// no parent, but its parent is unparented but the parent
|
||||
// hierarchy has been replaced by a new hierarchy with the same id
|
||||
// and it is safe to un-parent startView
|
||||
overlayView = startView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,6 +389,26 @@ public abstract class Visibility extends Transition {
|
||||
return null;
|
||||
}
|
||||
|
||||
private View copyViewImage(View view) {
|
||||
int width = view.getWidth();
|
||||
int height = view.getHeight();
|
||||
if (width <= 0 || height <= 0) {
|
||||
return null;
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
view.draw(canvas);
|
||||
final BitmapDrawable drawable = new BitmapDrawable(bitmap);
|
||||
|
||||
View overlayView = new View(view.getContext());
|
||||
overlayView.setBackground(drawable);
|
||||
int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
|
||||
int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
|
||||
overlayView.measure(widthSpec, heightSpec);
|
||||
overlayView.layout(0, 0, width, height);
|
||||
return overlayView;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of this method returns a null Animator. Subclasses should
|
||||
* override this method to make targets disappear with the desired transition. The
|
||||
|
||||
Reference in New Issue
Block a user