Compare commits

...

15 Commits

Author SHA1 Message Date
Eric Kuck fff9f76e8a Version bump 2016-03-31 14:12:23 -05:00
Eric Kuck bcc8f47856 Fixed tests to work with corrected lifecycle 2016-03-30 18:35:52 -05:00
Eric Kuck 61d68a9c6c Tweaks to ensure lifecycle callback chain remains intact when the activity is destroyed unexpectedly 2016-03-30 18:32:05 -05:00
Eric Kuck 5e7258973e Tweaks to ensure lifecycle callback chain remains intact when the activity is destroyed unexpectedly 2016-03-30 18:30:23 -05:00
Eric Kuck 194696e9cb Added a method for animating setting the root controller 2016-03-30 12:43:13 -05:00
Eric Kuck 5130909efc Fixed readme's controller implementation 2016-03-28 22:30:43 -05:00
Eric Kuck 7874c4f72d Typo fix 2016-03-26 19:21:42 -05:00
Eric Kuck 8399868a63 Minor lifecycle bug fixes 2016-03-26 19:19:02 -05:00
Eric Kuck 3e97e7f8a8 Minor demo app cleanup 2016-03-23 09:27:36 -05:00
Eric Kuck d5e54f33a0 Fixed issue with screen rotation 2016-03-22 14:42:31 -05:00
Eric Kuck 58d1f37db0 Test fix 2016-03-21 22:35:51 -05:00
Eric Kuck 7c175e4ce5 Fixed where the Controller's view is set internally 2016-03-21 22:30:56 -05:00
Eric Kuck 328b8a0873 Readme update 2016-03-21 11:55:46 -05:00
Eric Kuck db446279bb Added some basic lint checks 2016-03-21 11:30:13 -05:00
Eric Kuck 80042ea71d Minor demo app refactor 2016-03-20 00:04:22 -05:00
25 changed files with 429 additions and 85 deletions
+5 -5
View File
@@ -20,14 +20,14 @@ Conductor is architecture-agnostic and does not try to force any design decision
## Installation
```gradle
compile 'com.bluelinelabs:conductor:1.0.2'
compile 'com.bluelinelabs:conductor:1.0.5'
// If you want the components that go along with
// Android's support libraries (currently just a PagerAdapter):
compile 'com.bluelinelabs:conductor-support:1.0.2'
compile 'com.bluelinelabs:conductor-support:1.0.5'
// If you want RxJava/RxAndroid lifecycle support:
compile 'com.bluelinelabs:conductor-rxlifecycle:1.0.2'
compile 'com.bluelinelabs:conductor-rxlifecycle:1.0.5'
```
## Components to Know
@@ -78,8 +78,8 @@ public class MainActivity extends Activity {
public class HomeController extends Controller {
@Override
protected int layoutId() {
return R.layout.controller_overlay;
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_home, container, false);
}
@Override
+20
View File
@@ -0,0 +1,20 @@
apply plugin: 'java'
configurations {
lintChecks
}
dependencies {
compile rootProject.ext.lintapi
compile rootProject.ext.lintchecks
lintChecks files(jar)
}
jar {
manifest {
attributes('Lint-Registry': 'com.bluelinelabs.conductor.lint.IssueRegistry')
}
}
apply from: rootProject.file('dependencies.gradle')
@@ -0,0 +1,100 @@
package com.bluelinelabs.conductor.lint;
import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import lombok.ast.ClassDeclaration;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.StrictListAccessor;
import lombok.ast.TypeMember;
import lombok.ast.VariableDefinition;
public final class ControllerChangeHandlerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
public static final Issue ISSUE =
Issue.create("ValidControllerChangeHandler", "ControllerChangeHandler not instantiatable",
"Non-abstract ControllerChangeHandler instances must have a default constructor for the"
+ " system to re-create them in the case of the process being killed.",
Category.CORRECTNESS, 6, Severity.FATAL,
new Implementation(ControllerChangeHandlerIssueDetector.class, Scope.JAVA_FILE_SCOPE));
public ControllerChangeHandlerIssueDetector() { }
@NonNull
@Override
public Speed getSpeed() {
return Speed.FAST;
}
@Override
public List<String> applicableSuperClasses() {
return Collections.singletonList("com.bluelinelabs.conductor.ControllerChangeHandler");
}
@Override
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
if (node == null) {
return;
}
final int flags = node.astModifiers().getEffectiveModifierFlags();
if ((flags & Modifier.ABSTRACT) != 0) {
return;
}
if ((flags & Modifier.PUBLIC) == 0) {
String message = String.format("This ControllerChangeHandler class should be public (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
String message = String.format("This ControllerChangeHandler inner class should be static (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
boolean hasConstructor = false;
boolean hasDefaultConstructor = false;
NormalTypeBody body = node.astBody();
if (body != null) {
for (TypeMember member : body.astMembers()) {
if (member instanceof ConstructorDeclaration) {
hasConstructor = true;
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
if (constructor.astModifiers().isPublic()) {
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
if (params.isEmpty()) {
hasDefaultConstructor = true;
break;
}
}
}
}
}
if (hasConstructor && !hasDefaultConstructor) {
String message = String.format(
"This ControllerChangeHandler needs to have a public default constructor (`%1$s`)",
cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
}
}
}
@@ -0,0 +1,108 @@
package com.bluelinelabs.conductor.lint;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import lombok.ast.ClassDeclaration;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.StrictListAccessor;
import lombok.ast.TypeMember;
import lombok.ast.VariableDefinition;
public final class ControllerIssueDetector extends Detector implements Detector.JavaScanner, Detector.ClassScanner {
public static final Issue ISSUE =
Issue.create("ValidController", "Controller not instantiatable",
"Non-abstract Controller instances must have a default or single-argument constructor"
+ " that takes a Bundle in order for the system to re-create them in the"
+ " case of the process being killed.", Category.CORRECTNESS, 6, Severity.FATAL,
new Implementation(ControllerIssueDetector.class, Scope.JAVA_FILE_SCOPE));
public ControllerIssueDetector() { }
@NonNull
@Override
public Speed getSpeed() {
return Speed.FAST;
}
@Override
public List<String> applicableSuperClasses() {
return Collections.singletonList("com.bluelinelabs.conductor.Controller");
}
@Override
public void checkClass(@NonNull JavaContext context, ClassDeclaration node,
@NonNull Node declarationOrAnonymous, @NonNull ResolvedClass cls) {
if (node == null) {
return;
}
final int flags = node.astModifiers().getEffectiveModifierFlags();
if ((flags & Modifier.ABSTRACT) != 0) {
return;
}
if ((flags & Modifier.PUBLIC) == 0) {
String message = String.format("This Controller class should be public (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
if (cls.getContainingClass() != null && (flags & Modifier.STATIC) == 0) {
String message = String.format("This Controller inner class should be static (%1$s)", cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
return;
}
boolean hasConstructor = false;
boolean hasDefaultConstructor = false;
boolean hasBundleConstructor = false;
NormalTypeBody body = node.astBody();
if (body != null) {
for (TypeMember member : body.astMembers()) {
if (member instanceof ConstructorDeclaration) {
hasConstructor = true;
ConstructorDeclaration constructor = (ConstructorDeclaration)member;
if (constructor.astModifiers().isPublic()) {
StrictListAccessor<VariableDefinition, ConstructorDeclaration> params = constructor.astParameters();
if (params.isEmpty()) {
hasDefaultConstructor = true;
break;
} else if (params.size() == 1 &&
(params.first().astTypeReference().getTypeName().equals(SdkConstants.CLASS_BUNDLE)) ||
params.first().astTypeReference().getTypeName().equals("Bundle")) {
hasBundleConstructor = true;
break;
}
}
}
}
}
if (hasConstructor && !hasDefaultConstructor && !hasBundleConstructor) {
String message = String.format(
"This Controller needs to have either a public default constructor or a" +
" public single-argument constructor that takes a Bundle. (`%1$s`)",
cls.getName());
context.report(ISSUE, node, context.getLocation(node.astName()), message);
}
}
}
@@ -0,0 +1,14 @@
package com.bluelinelabs.conductor.lint;
import com.android.tools.lint.detector.api.Issue;
import java.util.Arrays;
import java.util.List;
public final class IssueRegistry extends com.android.tools.lint.client.api.IssueRegistry {
@Override public List<Issue> getIssues() {
return Arrays.asList(
ControllerIssueDetector.ISSUE,
ControllerChangeHandlerIssueDetector.ISSUE);
}
}
+18
View File
@@ -31,11 +31,17 @@ android {
}
}
configurations {
lintChecks
}
dependencies {
testCompile rootProject.ext.junit
testCompile rootProject.ext.roboelectric
compile rootProject.ext.supportAnnotations
lintChecks project(path: ':conductor-lint', configuration: 'lintChecks')
}
unMock {
@@ -46,6 +52,18 @@ unMock {
keep "android.text.TextUtils"
}
task copyLintJar(type: Copy) {
from(configurations.lintChecks) {
rename { 'lint.jar' }
}
into 'build/intermediates/lint/'
}
project.afterEvaluate {
def compileLintTask = project.tasks.find { it.name == 'compileLint' }
compileLintTask.dependsOn(copyLintJar)
}
ext.artifactId = 'conductor'
apply from: rootProject.file('dependencies.gradle')
@@ -67,10 +67,12 @@ class Backstack implements Iterable<RouterTransaction> {
mBackStack.push(transaction);
}
public void popAll() {
public List<RouterTransaction> popAll() {
List<RouterTransaction> list = new ArrayList<>();
while (!isEmpty()) {
pop();
list.add(pop());
}
return list;
}
public void saveInstanceState(Bundle outState) {
@@ -43,11 +43,12 @@ public class ChangeHandlerFrameLayout extends FrameLayout implements ControllerC
@Override
public void onChangeStarted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
mInProgressTransactionCount++;
mInProgressTransactionCount++;
}
@Override
public void onChangeCompleted(Controller to, Controller from, boolean isPush, ViewGroup container, ControllerChangeHandler handler) {
mInProgressTransactionCount--;
}
}
@@ -201,14 +201,16 @@ public abstract class Controller {
* Returns the Resources from the host Activity
*/
public final Resources getResources() {
return getActivity().getResources();
Activity activity = getActivity();
return activity != null ? activity.getResources() : null;
}
/**
* Returns the Application Context derived from the host Activity
*/
public final Context getApplicationContext() {
return getActivity().getApplicationContext();
Activity activity = getActivity();
return activity != null ? activity.getApplicationContext() : null;
}
/**
@@ -541,6 +543,10 @@ public abstract class Controller {
mOverriddenPopHandler = overriddenPopHandler;
}
final void prepareForConfigurationChange() {
mNeedsAttach = mNeedsAttach || mAttached;
}
final boolean getNeedsAttach() {
return mNeedsAttach;
}
@@ -622,7 +628,7 @@ public abstract class Controller {
if (isChangingConfigurations) {
removeViewReference();
} else {
destroy();
destroy(true);
}
for (ChildControllerTransaction child : mChildControllers) {
@@ -637,7 +643,6 @@ public abstract class Controller {
mAttached = true;
mNeedsAttach = false;
mView = view;
for (ChildControllerTransaction child : mChildControllers) {
attachChildController(child, new SimpleSwapChangeHandler());
@@ -726,14 +731,20 @@ public abstract class Controller {
}
final void destroy() {
destroy(false);
}
final void destroy(boolean removeViews) {
mIsBeingDestroyed = true;
for (ChildControllerTransaction child : mChildControllers) {
child.controller.destroy();
child.controller.destroy(removeViews);
}
if (!mAttached) {
removeViewReference();
} else if (removeViews) {
detach(mView);
}
}
@@ -850,6 +861,8 @@ public abstract class Controller {
lifecycleListener.preBindView(this, view);
}
mView = view;
onBindView(view);
view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.Controller.LifecycleListener;
import com.bluelinelabs.conductor.ControllerChangeHandler.ControllerChangeListener;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import com.bluelinelabs.conductor.internal.LifecycleHandler;
@@ -26,12 +27,13 @@ public class Router {
private LifecycleHandler mLifecycleHandler;
private ViewGroup mContainer;
private final List<ControllerChangeListener> mChangeListeners = new ArrayList<>();
private final List<Controller> mDestroyingControllers = new ArrayList<>();
/**
* Returns this Router's host Activity
*/
public Activity getActivity() {
return mLifecycleHandler.getLifecycleActivity();
return mLifecycleHandler != null ? mLifecycleHandler.getLifecycleActivity() : null;
}
/**
@@ -102,7 +104,7 @@ public class Router {
boolean poppingTopController = topController.controller == controller;
if (poppingTopController) {
mBackStack.pop();
trackDestroyingController(mBackStack.pop());
} else {
for (RouterTransaction transaction : mBackStack) {
if (transaction.controller == controller) {
@@ -140,7 +142,7 @@ public class Router {
public void replaceTopController(@NonNull RouterTransaction transaction) {
RouterTransaction topTransaction = mBackStack.peek();
if (!mBackStack.isEmpty()) {
mBackStack.pop();
trackDestroyingController(mBackStack.pop());
}
pushToBackstack(transaction);
@@ -199,12 +201,32 @@ public class Router {
}
/**
* Sets the root {@link Controller}. If any {@link Controller} are currently in the backstack, they will be removed.
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
*/
public void setRoot(@NonNull Controller controller) {
setRoot(controller, null);
setRoot(controller, null, null);
}
/**
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
* @param tag The tag to use for this {@link Controller}
*/
public void setRoot(@NonNull Controller controller, String tag) {
setRoot(controller, tag, null);
}
/**
* Sets the root {@link Controller}. If any {@link Controller}s are currently in the backstack, they will be removed.
*
* @param controller The new root {@link Controller}
* @param changeHandler The {@link ControllerChangeHandler} to use for setting the root
*/
public void setRoot(@NonNull Controller controller, ControllerChangeHandler changeHandler) {
setRoot(controller, null, changeHandler);
}
/**
@@ -212,14 +234,15 @@ public class Router {
*
* @param controller The new root {@link Controller}
* @param tag The tag to use for this {@link Controller}
* @param changeHandler The {@link ControllerChangeHandler} to use for setting the root
*/
public void setRoot(@NonNull Controller controller, String tag) {
public void setRoot(@NonNull Controller controller, String tag, ControllerChangeHandler changeHandler) {
mContainer.removeAllViews();
mBackStack.popAll();
trackDestroyingControllers(mBackStack.popAll());
RouterTransaction transaction = RouterTransaction.builder(controller)
.tag(tag)
.pushChangeHandler(new SimpleSwapChangeHandler())
.pushChangeHandler(changeHandler != null ? changeHandler : new SimpleSwapChangeHandler())
.popChangeHandler(new SimpleSwapChangeHandler())
.build();
@@ -335,18 +358,29 @@ public class Router {
}
public final void onActivitySaveInstanceState(Activity activity, Bundle outState) {
if (activity.isChangingConfigurations()) {
for (RouterTransaction transaction : mBackStack) {
transaction.controller.prepareForConfigurationChange();
}
}
mBackStack.saveInstanceState(outState);
}
public final void onActivityDestroyed(Activity activity) {
mContainer.setOnHierarchyChangeListener(null);
mLifecycleHandler = null;
mContainer = null;
mChangeListeners.clear();
for (RouterTransaction transaction : mBackStack) {
transaction.controller.activityDestroyed(activity.isChangingConfigurations());
}
for (Controller controller : mDestroyingControllers) {
controller.activityDestroyed(activity.isChangingConfigurations());
}
mLifecycleHandler = null;
mContainer = null;
}
public final void onRestoreInstanceState(Bundle savedInstanceState) {
@@ -356,6 +390,7 @@ public class Router {
private void popToTransaction(@NonNull RouterTransaction transaction, ControllerChangeHandler changeHandler) {
RouterTransaction topTransaction = mBackStack.peek();
List<RouterTransaction> poppedTransactions = mBackStack.popTo(transaction);
trackDestroyingControllers(poppedTransactions);
if (poppedTransactions.size() > 0) {
if (changeHandler == null) {
@@ -430,4 +465,21 @@ public class Router {
mBackStack.push(entry);
}
private void trackDestroyingController(RouterTransaction transaction) {
mDestroyingControllers.add(transaction.controller);
transaction.controller.addLifecycleListener(new LifecycleListener() {
@Override
public void postDestroy(@NonNull Controller controller) {
mDestroyingControllers.remove(controller);
}
});
}
private void trackDestroyingControllers(List<RouterTransaction> transactions) {
for (RouterTransaction transaction : transactions) {
trackDestroyingController(transaction);
}
}
}
@@ -119,6 +119,11 @@ public abstract class AnimatorChangeHandler extends ControllerChangeHandler {
}
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
changeListener.onChangeCompleted();
}
@Override
public void onAnimationEnd(Animator animation) {
if (from != null && (!isPush || mRemovesFromViewOnPush)) {
@@ -3,7 +3,6 @@ package com.bluelinelabs.conductor.changehandler;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.ControllerChangeHandler;
@@ -44,19 +43,10 @@ public class SimpleSwapChangeHandler extends ControllerChangeHandler {
}
if (to != null && to.getParent() == null) {
to.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
view.removeOnAttachStateChangeListener(this);
changeListener.onChangeCompleted();
}
@Override
public void onViewDetachedFromWindow(View v) { }
});
container.addView(to);
}
changeListener.onChangeCompleted();
}
}
@@ -94,7 +94,6 @@ public class ControllerTests {
assertCalls(1, 1, 1, 1, 0, 0, 0);
mActivityController.destroy();
ViewUtils.setAttached(controller.getView(), false);
assertCalls(1, 1, 1, 1, 1, 1, 1);
}
@@ -180,7 +179,7 @@ public class ControllerTests {
controller.setRetainViewMode(RetainViewMode.RELEASE_DETACH);
Assert.assertNull(controller.getView());
View view = controller.inflate(new FrameLayout(mRouter.getActivity()));
Assert.assertNull(controller.getView());
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, true);
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, false);
@@ -189,7 +188,7 @@ public class ControllerTests {
// Test View getting retained w/ RETAIN_DETACH
controller.setRetainViewMode(RetainViewMode.RETAIN_DETACH);
view = controller.inflate(new FrameLayout(mRouter.getActivity()));
Assert.assertNull(controller.getView());
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, true);
Assert.assertNotNull(controller.getView());
ViewUtils.setAttached(view, false);
@@ -279,7 +278,7 @@ public class ControllerTests {
void performChange(@NonNull ViewGroup container, View from, View to, boolean isPush, @NonNull ControllerChangeCompletedListener changeListener);
}
static class ChangeHandler extends ControllerChangeHandler {
public static class ChangeHandler extends ControllerChangeHandler {
private ChangeHandlerListener mListener;
+3
View File
@@ -45,6 +45,9 @@ dependencies {
compile 'com.bluelinelabs:conductor-support:' + rootProject.ext.publishedVersionName
compile 'com.bluelinelabs:conductor-rxlifecycle:' + rootProject.ext.publishedVersionName
// compile project(':conductor-support')
// compile project(':conductor-rxlifecycle')
debugCompile rootProject.ext.leakCanary
releaseCompile rootProject.ext.leakCanaryNoOp
testCompile rootProject.ext.leakCanaryNoOp
+5 -2
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:tools="http://schemas.android.com/tools"
package="com.bluelinelabs.conductor.demo"
xmlns:android="http://schemas.android.com/apk/res/android">
@@ -7,11 +8,13 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:name="com.bluelinelabs.conductor.demo.App"
android:name="com.bluelinelabs.conductor.demo.DemoApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:fullBackupContent="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name="com.bluelinelabs.conductor.demo.MainActivity"
@@ -5,7 +5,7 @@ import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
public class App extends Application {
public class DemoApplication extends Application {
public static RefWatcher refWatcher;
@@ -8,7 +8,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
@@ -9,7 +9,7 @@ import android.widget.TextView;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
import com.bluelinelabs.conductor.demo.util.ColorUtil;
@@ -14,8 +14,6 @@ import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
import com.bluelinelabs.conductor.demo.util.ColorUtil;
import java.util.List;
public class ParentController extends RefWatchingController {
private static final int NUMBER_OF_CHILDREN = 5;
@@ -37,15 +35,38 @@ public class ParentController extends RefWatchingController {
}
private void addChild(final int index) {
int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
String tag = Integer.toString(index);
ChildController childController = new ChildController("Child Controller #" + index, ColorUtil.getMaterialColor(getResources(), index), false);
addChildController(ChildControllerTransaction.builder(childController, frameId)
.pushChangeHandler(new FadeChangeHandler())
.popChangeHandler(new FadeChangeHandler())
.build());
if (getChildController(tag) == null) {
int frameId = getResources().getIdentifier("child_content_" + (index + 1), "id", getActivity().getPackageName());
childController.addLifecycleListener(new LifecycleListener() {
ChildController childController = new ChildController("Child Controller #" + index, ColorUtil.getMaterialColor(getResources(), index), false);
addChildController(ChildControllerTransaction.builder(childController, frameId)
.pushChangeHandler(new FadeChangeHandler())
.popChangeHandler(new FadeChangeHandler())
.tag(tag)
.build());
}
}
private void removeChild(int index) {
removeChildController(getChildControllers().get(index));
}
@Override
public boolean handleBack() {
if (getChildControllers().size() == NUMBER_OF_CHILDREN && !mFinishing) {
mFinishing = true;
removeChild(getChildControllers().size() - 1);
}
return true;
}
@Override
public void addChildController(ChildControllerTransaction transaction) {
final int index = Integer.parseInt(transaction.tag);
transaction.controller.addLifecycleListener(new LifecycleListener() {
@Override
public void onChangeEnd(@NonNull Controller controller, @NonNull ControllerChangeHandler changeHandler, @NonNull ControllerChangeType changeType) {
if (changeType == ControllerChangeType.PUSH_ENTER && index < NUMBER_OF_CHILDREN - 1) {
@@ -59,19 +80,7 @@ public class ParentController extends RefWatchingController {
}
}
});
}
private void removeChild(int index) {
List<Controller> childControllers = getChildControllers();
removeChildController(childControllers.get(index));
}
@Override
public boolean handleBack() {
if (getChildControllers().size() == NUMBER_OF_CHILDREN && !mFinishing) {
mFinishing = true;
removeChild(getChildControllers().size() - 1);
}
return true;
super.addChildController(transaction);
}
}
@@ -7,7 +7,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.controllers.base.RefWatchingController;
@@ -19,7 +19,7 @@ import com.bluelinelabs.conductor.changehandler.CircularRevealChangeHandler;
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.conductor.demo.BundleBuilder;
import com.bluelinelabs.conductor.demo.util.BundleBuilder;
import com.bluelinelabs.conductor.demo.R;
import com.bluelinelabs.conductor.demo.changehandler.ArcFadeMoveChangeHandlerCompat;
import com.bluelinelabs.conductor.demo.changehandler.FlipChangeHandler;
@@ -58,7 +58,7 @@ public class TransitionDemoController extends RefWatchingController {
@Bind(R.id.tv_title) TextView mTvTitle;
@Bind(R.id.btn_next) FloatingActionButton mBtnNext;
View mContainerView;
@Bind(R.id.transition_root) View mContainerView;
private TransitionDemo mTransitionDemo;
@@ -73,6 +73,12 @@ public class TransitionDemoController extends RefWatchingController {
mTransitionDemo = TransitionDemo.fromIndex(args.getInt(KEY_INDEX));
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(mTransitionDemo.layoutId, container, false);
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
@@ -92,16 +98,9 @@ public class TransitionDemoController extends RefWatchingController {
}
mBtnNext.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(getActivity(), buttonColor)));
mContainerView = view;
mTvTitle.setText(mTransitionDemo.title);
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(mTransitionDemo.layoutId, container, false);
}
@OnClick(R.id.btn_next) void onNextClicked() {
final int nextIndex = mTransitionDemo.ordinal() + 1;
@@ -143,4 +142,5 @@ public class TransitionDemoController extends RefWatchingController {
.popChangeHandler(changeHandler)
.build();
}
}
@@ -4,7 +4,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import com.bluelinelabs.conductor.demo.App;
import com.bluelinelabs.conductor.demo.DemoApplication;
public abstract class RefWatchingController extends ButterKnifeController {
@@ -18,16 +18,16 @@ public abstract class RefWatchingController extends ButterKnifeController {
super.onDetach(view);
if (isDestroyed()) {
App.refWatcher.watch(view);
DemoApplication.refWatcher.watch(view);
}
}
@Override
public void onDestroy() {
if (getView() != null) {
App.refWatcher.watch(getView());
DemoApplication.refWatcher.watch(getView());
}
App.refWatcher.watch(this);
DemoApplication.refWatcher.watch(this);
}
}
@@ -1,4 +1,4 @@
package com.bluelinelabs.conductor.demo;
package com.bluelinelabs.conductor.demo.util;
import android.os.Bundle;
import android.os.Parcelable;
+6 -3
View File
@@ -5,8 +5,8 @@ ext {
buildToolsVersion = '23.0.2'
versionCode = 1
versionName = '1.0.2'
publishedVersionName = '1.0.2'
versionName = '1.0.5'
publishedVersionName = '1.0.5'
supportV4 = 'com.android.support:support-v4:23.1.1'
supportDesign = 'com.android.support:design:23.1.1'
@@ -24,4 +24,7 @@ ext {
junit = 'junit:junit:4.11'
roboelectric = 'org.robolectric:robolectric:3.0'
}
lintapi = 'com.android.tools.lint:lint-api:24.5.0'
lintchecks = 'com.android.tools.lint:lint-checks:24.5.0'
}
+5 -1
View File
@@ -1 +1,5 @@
include ':conductor', ':conductor-support', ':conductor-rxlifecycle', ':demo'
include ':conductor'
include':conductor-support'
include':conductor-rxlifecycle'
include':conductor-lint'
include':demo'