diff --git a/conductor/src/main/java/com/bluelinelabs/conductor/Controller.java b/conductor/src/main/java/com/bluelinelabs/conductor/Controller.java index 51efb347..c2ce132e 100644 --- a/conductor/src/main/java/com/bluelinelabs/conductor/Controller.java +++ b/conductor/src/main/java/com/bluelinelabs/conductor/Controller.java @@ -238,6 +238,65 @@ public final Router getChildRouter(@NonNull ViewGroup container, @Nullable Strin return childRouter; } + public interface TabControllerFactory { + RouterTransaction getRootControllerForTab(); + } + + private ControllerHostedRouter previousTabRouter = null; + + @NonNull + public final Router switchChildRouterForTab( + @NonNull ViewGroup container, + @Nullable String tag, + TabControllerFactory controllerFactory) { + + @IdRes final int containerId = container.getId(); + + ControllerHostedRouter currentRouter = null; + for (ControllerHostedRouter router : childRouters) { + if (router.getHostId() == containerId && TextUtils.equals(tag, router.getTag())) { + currentRouter = router; + break; + } + } + + if (currentRouter == null) { + currentRouter = new ControllerHostedRouter(container.getId(), tag); + currentRouter.setHost(this, container); + childRouters.add(currentRouter); + + if (isPerformingExitTransition) { + currentRouter.setDetachFrozen(true); + } + + } else { + currentRouter.prepareForHostTabAttach(); + + if (!currentRouter.hasHost()) { + currentRouter.setHost(this, container); + } + } + + if (!currentRouter.hasRootController()) { + currentRouter.setRootForTab(controllerFactory.getRootControllerForTab()); + } + + currentRouter.switchTabRouter(previousTabRouter == null ? null : previousTabRouter.backstack.peek()); + + + if (previousTabRouter != null) { + container.post(new Runnable() { + @Override + public void run() { + previousTabRouter.removeHost(); + } + }); + } + + previousTabRouter = currentRouter; + return currentRouter; + } + /** * Removes a child {@link Router} from this Controller. When removed, all Controllers currently managed by * the {@link Router} will be destroyed. diff --git a/conductor/src/main/java/com/bluelinelabs/conductor/Router.java b/conductor/src/main/java/com/bluelinelabs/conductor/Router.java index aa56ba96..aa48e127 100644 --- a/conductor/src/main/java/com/bluelinelabs/conductor/Router.java +++ b/conductor/src/main/java/com/bluelinelabs/conductor/Router.java @@ -17,6 +17,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler.ChangeTransaction; import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener; import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler; +import com.bluelinelabs.conductor.changehandler.SwapTabChangeHandler; import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler; import com.bluelinelabs.conductor.internal.ThreadUtils; import com.bluelinelabs.conductor.internal.TransactionIndexer; @@ -497,6 +498,44 @@ public void setBackstack(@NonNull List newBackstack, @Nullabl } } + @SuppressWarnings("WeakerAccess") + @UiThread + public void switchTabRouter(@Nullable RouterTransaction from) { + ThreadUtils.ensureMainThread(); + + Iterator backstackIterator = backstack.reverseIterator(); + while (backstackIterator.hasNext()) { + RouterTransaction transaction = backstackIterator.next(); + + if (transaction.controller.getNeedsAttach()) { + ControllerChangeHandler handler = new SwapTabChangeHandler(); + performControllerChange(transaction, from, true, handler); + } + } + } + + @SuppressWarnings("WeakerAccess") + @UiThread + public void setRootForTab(@NonNull RouterTransaction rootTransaction) { + ThreadUtils.ensureMainThread(); + + rootTransaction.controller.setNeedsAttach(true); + List rootTransactions = Collections.singletonList(rootTransaction); + + removeAllExceptVisibleAndUnowned(); + ensureOrderedTransactionIndices(rootTransactions); + + backstack.setBackstack(rootTransactions); + + // Ensure all new controllers have a valid router set + Iterator backstackIterator = backstack.reverseIterator(); + while (backstackIterator.hasNext()) { + RouterTransaction transaction = backstackIterator.next(); + transaction.onAttachedToRouter(); + setControllerRouter(transaction.controller); + } + } + /** * Returns whether or not this Router has a root {@link Controller} */ @@ -618,6 +657,14 @@ public void onActivityDestroyed(@NonNull Activity activity) { container = null; } + public void prepareForHostTabAttach() { + RouterTransaction transaction = backstack.peek(); + if (transaction != null){ + transaction.controller.setNeedsAttach(true); + transaction.controller.prepareForHostDetach(); + } + } + public void prepareForHostDetach() { for (RouterTransaction transaction : backstack) { if (ControllerChangeHandler.completeHandlerImmediately(transaction.controller.getInstanceId())) { diff --git a/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SimpleSwapChangeHandler.java b/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SimpleSwapChangeHandler.java old mode 100644 new mode 100755 index 5d845511..5b66fe86 --- a/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SimpleSwapChangeHandler.java +++ b/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SimpleSwapChangeHandler.java @@ -19,10 +19,10 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler implements private boolean removesFromViewOnPush; - private boolean canceled; + protected boolean canceled; - private ViewGroup container; - private ControllerChangeCompletedListener changeListener; + protected ViewGroup container; + protected ControllerChangeCompletedListener changeListener; public SimpleSwapChangeHandler() { this(true); diff --git a/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SwapTabChangeHandler.java b/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SwapTabChangeHandler.java new file mode 100755 index 00000000..523af6ac --- /dev/null +++ b/conductor/src/main/java/com/bluelinelabs/conductor/changehandler/SwapTabChangeHandler.java @@ -0,0 +1,40 @@ +package com.bluelinelabs.conductor.changehandler; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.View; +import android.view.ViewGroup; + +import com.bluelinelabs.conductor.ControllerChangeHandler; + +/** + * A {@link ControllerChangeHandler} that will instantly swap Views with no animations or transitions. + */ +public class SwapTabChangeHandler extends SimpleSwapChangeHandler { + + public SwapTabChangeHandler() { + } + + + @Override + public void performChange(@NonNull ViewGroup container, @Nullable View from, @Nullable View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener) { + if (!canceled) { + if (from != null) { + container.removeView(from); + } + + if (to != null && to.getParent() == null) { + container.addView(to); + } + } + + if (container.getWindowToken() != null) { + changeListener.onChangeCompleted(); + } else { + this.changeListener = changeListener; + this.container = container; + container.addOnAttachStateChangeListener(this); + } + + } +}