根据@lukas 的回答和他的图书馆flow-navigation
,我意识到破坏的违规调用MortarScope
是这一行:
oldPath.destroyNotIn(context, contextFactory);
所以我用
public static PathContext create(PathContext previousContext, Path newPath, PathContextFactory factory) {
if(newPath == Path.ROOT) {
throw new IllegalArgumentException("Path is empty.");
}
List<Path> newPathElements = newPath.elements();
Map<Path, Context> newContextChain = new LinkedHashMap<>();
// We walk down the elements, reusing existing contexts for the elements we encounter. As soon
// as we encounter an element that doesn't already have a context, we stop.
// Note: we will always have at least one shared element, the root.
Context baseContext = null;
Iterator<Path> pathIterator = newPathElements.iterator();
Iterator<Path> basePathIterator = previousContext.path.elements().iterator();
Log.d("PathContext", ":: Creating Context to [" + ((BasePath) newPath).getScopeName() + "]");
while(pathIterator.hasNext() && basePathIterator.hasNext()) {
Path element = pathIterator.next();
Path basePathElement = basePathIterator.next();
if(basePathElement.equals(element)) {
if(!element.isRoot()) {
Log.d("PathContext",
"Matched new Path to old Path [" + ((BasePath) element).getScopeName() + "], preserving context.");
} else {
Log.d("PathContext", "Matched new Path to old Path [ROOT], preserving context.");
}
baseContext = previousContext.contexts.get(element);
newContextChain.put(element, baseContext);
} else {
if(!basePathElement.isRoot() && !element.isRoot()) {
Log.d("PathContext",
"No match from [" + ((BasePath) basePathElement).getScopeName() + "] to [" + ((BasePath) element)
.getScopeName() + "] , creating new context.");
} else {
Log.d("PathContext",
"No match from ROOT [" + basePathElement + "] to ROOT [" + element + "] , creating new context.");
}
baseContext = factory.setUpContext(element, baseContext);
newContextChain.put(element, baseContext);
break;
}
}
// Now we continue walking our new path, creating contexts as we go in case they don't exist.
while(pathIterator.hasNext()) {
Path element = pathIterator.next();
if(!element.isRoot()) {
Log.d("PathContext", "Creating new path [" + ((BasePath) element).getScopeName() + "].");
} else {
Log.d("PathContext", "Creating new path [ROOT].");
}
baseContext = factory.setUpContext(element, baseContext);
newContextChain.put(element, baseContext);
}
// Finally, we can construct our new PathContext
return new PathContext(baseContext, newPath, newContextChain);
}
/**
* Finds the tail of this path which is not in the given path, and destroys it.
*/
public void destroyNotIn(PathContext path, PathContextFactory factory) {
Iterator<Path> aElements = this.path.elements().iterator();
Iterator<Path> bElements = path.path.elements().iterator();
while(aElements.hasNext() && bElements.hasNext()) {
Path aElement = aElements.next();
Path bElement = bElements.next();
if(!aElement.equals(bElement)) {
BasePath aBasePath = (BasePath) aElement;
BasePath bBasePath = (BasePath) bElement;
Log.d(toString(),
"Destroying [" + aBasePath.getScopeName() + "] on matching with [" + bBasePath.getScopeName() + "]");
factory.tearDownContext(contexts.get(aElement));
break;
}
}
while(aElements.hasNext()) {
Path aElement = aElements.next();
BasePath aBasePath = (BasePath) aElement;
Log.d(toString(), "Destroying [" + aBasePath.getScopeName() + "] as it is not found in [" + path + "]");
factory.tearDownContext(contexts.get(aElement));
}
}
BasePath
只是返回getScopeName()
。它本质上就像BluePrint
Square 删除的那样。
还有,SimplePathContainer
之前的都毁了,所以我也修改了。
/**
* Provides basic right-to-left transitions. Saves and restores view state.
* Uses {@link PathContext} to allow customized sub-containers.
*/
public class SimplePathContainer
extends PathContainer {
private static final String TAG = "SimplePathContainer";
private final PathContextFactory contextFactory;
public SimplePathContainer(int tagKey, PathContextFactory contextFactory) {
super(tagKey);
this.contextFactory = contextFactory;
}
@Override
protected void performTraversal(final ViewGroup containerView, Flow.Traversal traversal, final PathContainer.TraversalState traversalState, final Flow.Direction direction, final Flow.TraversalCallback callback) {
final PathContext oldPathContext;
final PathContext newPathContext;
if(containerView.getChildCount() > 0) {
Log.d(TAG,
"Container View Child count was > 0, using view context of path [" + PathContext.get(containerView.getChildAt(
0).getContext()).path + "]");
oldPathContext = PathContext.get(containerView.getChildAt(0).getContext());
} else {
Log.d(TAG, "Container View Child Count was == 0, using root context");
oldPathContext = PathContext.root(containerView.getContext());
}
Log.d(TAG, "Previous Path [" + oldPathContext.path + "]");
final Path to = traversalState.toPath();
Log.d(TAG, "New Path [" + to + "]");
View newView;
newPathContext = PathContext.create(oldPathContext, to, contextFactory);
int layout = ((BasePath) to).getLayout(); //removed annotation
newView = LayoutInflater.from(newPathContext.getApplicationContext()) //fixed first path error
.cloneInContext(newPathContext)
.inflate(layout, containerView, false);
View fromView = null;
if(traversalState.fromPath() != null) {
fromView = containerView.getChildAt(0);
traversalState.saveViewState(fromView);
}
traversalState.restoreViewState(newView);
if(fromView == null || direction == REPLACE) {
containerView.removeAllViews();
containerView.addView(newView);
oldPathContext.destroyNotIn(newPathContext, contextFactory);
callback.onTraversalCompleted();
} else {
final View finalFromView = fromView;
if(direction == Flow.Direction.BACKWARD) {
containerView.removeView(fromView);
containerView.addView(newView);
containerView.addView(finalFromView);
} else {
containerView.addView(newView);
}
ViewUtils.waitForMeasure(newView, new ViewUtils.OnMeasuredCallback() {
@Override
public void onMeasured(View view, int width, int height) {
runAnimation(containerView, finalFromView, view, direction, new Flow.TraversalCallback() {
@Override
public void onTraversalCompleted() {
containerView.removeView(finalFromView);
oldPathContext.destroyNotIn(newPathContext, contextFactory);
callback.onTraversalCompleted();
}
}, (BasePath) Path.get(oldPathContext), (BasePath) to);
}
});
}
}
private void runAnimation(final ViewGroup container, final View from, final View to, Flow.Direction direction, final Flow.TraversalCallback callback, BasePath fromPath, BasePath toPath) {
Animator animator = createSegue(from, to, direction);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
container.removeView(from);
callback.onTraversalCompleted();
}
});
animator.start();
}
private Animator createSegue(View from, View to, Flow.Direction direction) {
boolean backward = direction == Flow.Direction.BACKWARD;
int fromTranslation = backward ? from.getWidth() : -from.getWidth();
int toTranslation = backward ? -to.getWidth() : to.getWidth();
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator.ofFloat(from, View.TRANSLATION_X, fromTranslation));
set.play(ObjectAnimator.ofFloat(to, View.TRANSLATION_X, toTranslation, 0));
return set;
}
}