Browse Source

V2 topbar (#1996)

* animation fix

* fix tests

* hide toolbar

* default values

* default values

* tmp commit

* tests

* animated hide

* animated hode improve

* fix topbar

* readme

* lifecycle WIP

* lifecycle alert delay hack

* test fixes

* move topbar to container

* fix tests

* refactor

* refactor WIP

* refactor fix tests

* nav options fallback to parse

* WIP

* topbar background fix
Roman Kozlov 6 years ago
parent
commit
26f36b0ba7
21 changed files with 415 additions and 129 deletions
  1. 1
    1
      README.md
  2. 108
    1
      lib/android/app/src/main/java/com/reactnativenavigation/anim/StackAnimator.java
  3. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  4. 45
    11
      lib/android/app/src/main/java/com/reactnativenavigation/parse/NavigationOptions.java
  5. 45
    8
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  6. 2
    0
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  7. 21
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java
  8. 2
    0
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java
  9. 10
    32
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  10. 12
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  11. 65
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopbarContainerView.java
  12. 23
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopbarContainerViewCreator.java
  13. 2
    1
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleContainerViewController.java
  14. 7
    0
      lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestContainerView.java
  15. 3
    0
      lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java
  16. 0
    15
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java
  17. 39
    26
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  18. 1
    0
      lib/ios/RNNNavigationOptions.h
  19. 17
    20
      lib/ios/RNNNavigationOptions.m
  20. 5
    5
      playground/src/containers/LifecycleScreen.js
  21. 4
    2
      playground/src/containers/OptionsScreen.js

+ 1
- 1
README.md View File

75
 | topBarTextFontFamily  |  ✅     |      ✅     |     ✅        | Wix |
75
 | topBarTextFontFamily  |  ✅     |      ✅     |     ✅        | Wix |
76
 | topBarBackgroundColor |  ✅     |  ✅       |     ✅         | Wix|
76
 | topBarBackgroundColor |  ✅     |  ✅       |     ✅         | Wix|
77
 | topBarButtonColor     |  ✅     |    ✅      |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
77
 | topBarButtonColor     |  ✅     |    ✅      |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
78
-| topBarHidden          |   ✅    |   ✅      |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
78
+| topBarHidden          |   ✅    |   ✅      |             | Wix|
79
 | topBarHideOnScroll    |  ✅     |  ✅    |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
79
 | topBarHideOnScroll    |  ✅     |  ✅    |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
80
 | topBarTranslucent     |  ✅     |   ✅     |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
80
 | topBarTranslucent     |  ✅     |   ✅     |     [Contribute](/docs/docs/CONTRIBUTING.md)        | Wix|
81
 | topBarTransparent     | ✅      |   WIP @bogobogo     |     [Contribute](/docs/docs/CONTRIBUTING.md)        |
81
 | topBarTransparent     | ✅      |   WIP @bogobogo     |     [Contribute](/docs/docs/CONTRIBUTING.md)        |

+ 108
- 1
lib/android/app/src/main/java/com/reactnativenavigation/anim/StackAnimator.java View File

3
 import android.animation.Animator;
3
 import android.animation.Animator;
4
 import android.animation.AnimatorSet;
4
 import android.animation.AnimatorSet;
5
 import android.animation.ObjectAnimator;
5
 import android.animation.ObjectAnimator;
6
+import android.animation.ValueAnimator;
6
 import android.app.Activity;
7
 import android.app.Activity;
7
 import android.content.Context;
8
 import android.content.Context;
8
 import android.support.annotation.Nullable;
9
 import android.support.annotation.Nullable;
9
 import android.util.DisplayMetrics;
10
 import android.util.DisplayMetrics;
11
+import android.util.Log;
10
 import android.view.View;
12
 import android.view.View;
13
+import android.view.ViewGroup;
11
 import android.view.WindowManager;
14
 import android.view.WindowManager;
12
 import android.view.animation.AccelerateInterpolator;
15
 import android.view.animation.AccelerateInterpolator;
13
 import android.view.animation.DecelerateInterpolator;
16
 import android.view.animation.DecelerateInterpolator;
17
+import android.widget.FrameLayout;
18
+import android.widget.LinearLayout;
19
+import android.widget.RelativeLayout;
20
+
21
+import com.reactnativenavigation.views.TopBar;
14
 
22
 
15
 @SuppressWarnings("ResourceType")
23
 @SuppressWarnings("ResourceType")
16
 public class StackAnimator {
24
 public class StackAnimator {
20
 	}
28
 	}
21
 
29
 
22
 	private static final int DURATION = 300;
30
 	private static final int DURATION = 300;
23
-	private static final int START_DELAY = 100;
31
+	private static final int DURATION_TOPBAR = 300;
24
 	private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
32
 	private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
25
 	private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
33
 	private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
26
 	private float translationY;
34
 	private float translationY;
109
 		return metrics.heightPixels;
117
 		return metrics.heightPixels;
110
 	}
118
 	}
111
 
119
 
120
+	public void animateShowTopBar(final TopBar topBar, final View container) {
121
+		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() - topBar.getMeasuredHeight());
122
+		containerHeightAnim.setInterpolator(DECELERATE_INTERPOLATOR);
123
+		containerHeightAnim.setDuration(DURATION_TOPBAR);
124
+		containerHeightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
125
+			@Override
126
+			public void onAnimationUpdate(ValueAnimator valueAnimator) {
127
+				int val = (Integer) valueAnimator.getAnimatedValue();
128
+				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
129
+				layoutParams.height = val;
130
+				container.setLayoutParams(layoutParams);
131
+			}
132
+		});
133
+		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, -1 * topBar.getMeasuredHeight(), 0);
134
+		containerTransitionAnim.setInterpolator(DECELERATE_INTERPOLATOR);
135
+		containerTransitionAnim.setDuration(DURATION_TOPBAR);
136
+
137
+		ObjectAnimator topbarAnim = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, -1 * topBar.getHeight(), 0);
138
+		topbarAnim.setInterpolator(DECELERATE_INTERPOLATOR);
139
+		topbarAnim.setDuration(DURATION_TOPBAR);
140
+
141
+		AnimatorSet set = new AnimatorSet();
142
+		set.addListener(new Animator.AnimatorListener() {
143
+			@Override
144
+			public void onAnimationStart(Animator animation) {
145
+				topBar.setVisibility(View.VISIBLE);
146
+			}
147
+
148
+			@Override
149
+			public void onAnimationEnd(Animator animation) {
150
+				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
151
+				layoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
152
+				container.setLayoutParams(layoutParams);
153
+			}
154
+
155
+			@Override
156
+			public void onAnimationCancel(Animator animation) {
157
+
158
+			}
159
+
160
+			@Override
161
+			public void onAnimationRepeat(Animator animation) {
162
+
163
+			}
164
+		});
165
+		set.playTogether(containerHeightAnim, containerTransitionAnim, topbarAnim);
166
+		set.start();
167
+	}
168
+
169
+	public void animateHideTopBar(final TopBar topBar, final View container) {
170
+		ValueAnimator containerHeightAnim = ValueAnimator.ofInt(container.getMeasuredHeight(), container.getMeasuredHeight() + topBar.getMeasuredHeight());
171
+		containerHeightAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
172
+		containerHeightAnim.setDuration(DURATION_TOPBAR);
173
+		containerHeightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
174
+			@Override
175
+			public void onAnimationUpdate(ValueAnimator valueAnimator) {
176
+				int val = (Integer) valueAnimator.getAnimatedValue();
177
+				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
178
+				layoutParams.height = val;
179
+				container.setLayoutParams(layoutParams);
180
+			}
181
+		});
182
+		ObjectAnimator containerTransitionAnim = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, 0, -1 * topBar.getMeasuredHeight());
183
+		containerTransitionAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
184
+		containerTransitionAnim.setDuration(DURATION_TOPBAR);
185
+
186
+		ObjectAnimator topbarAnim = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, 0, -1 * topBar.getMeasuredHeight());
187
+		topbarAnim.setInterpolator(ACCELERATE_INTERPOLATOR);
188
+		topbarAnim.setDuration(DURATION_TOPBAR);
189
+
190
+		AnimatorSet set = new AnimatorSet();
191
+		set.addListener(new Animator.AnimatorListener() {
192
+			@Override
193
+			public void onAnimationStart(Animator animation) {
194
+			}
195
+
196
+			@Override
197
+			public void onAnimationEnd(Animator animation) {
198
+				LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) container.getLayoutParams();
199
+				layoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
200
+				container.setLayoutParams(layoutParams);
201
+				container.setTranslationY(0);
202
+
203
+				topBar.setVisibility(View.GONE);
204
+				topBar.setTranslationY(0);
205
+			}
206
+
207
+			@Override
208
+			public void onAnimationCancel(Animator animation) {
209
+
210
+			}
211
+
212
+			@Override
213
+			public void onAnimationRepeat(Animator animation) {
112
 
214
 
215
+			}
216
+		});
217
+		set.playTogether(containerHeightAnim, containerTransitionAnim, topbarAnim);
218
+		set.start();
219
+	}
113
 }
220
 }

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java View File

9
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
9
 import com.reactnativenavigation.viewcontrollers.SideMenuController;
10
 import com.reactnativenavigation.viewcontrollers.StackController;
10
 import com.reactnativenavigation.viewcontrollers.StackController;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
12
+import com.reactnativenavigation.views.TopbarContainerViewCreator;
12
 
13
 
13
 import java.util.ArrayList;
14
 import java.util.ArrayList;
14
 import java.util.List;
15
 import java.util.List;
81
 		String id = node.id;
82
 		String id = node.id;
82
 		String name = node.data.optString("name");
83
 		String name = node.data.optString("name");
83
 		NavigationOptions navigationOptions = NavigationOptions.parse(node.data.optJSONObject("navigationOptions"));
84
 		NavigationOptions navigationOptions = NavigationOptions.parse(node.data.optJSONObject("navigationOptions"));
84
-		return new ContainerViewController(activity, id, name, new ReactContainerViewCreator(reactInstanceManager), navigationOptions);
85
+		return new ContainerViewController(activity, id, name,
86
+				new TopbarContainerViewCreator(new ReactContainerViewCreator(reactInstanceManager)), navigationOptions);
85
 	}
87
 	}
86
 
88
 
87
 	private ViewController createContainerStack(LayoutNode node) {
89
 	private ViewController createContainerStack(LayoutNode node) {

+ 45
- 11
lib/android/app/src/main/java/com/reactnativenavigation/parse/NavigationOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
+import android.graphics.Color;
3
 import android.support.annotation.ColorInt;
4
 import android.support.annotation.ColorInt;
4
 import android.support.annotation.NonNull;
5
 import android.support.annotation.NonNull;
5
 
6
 
7
 
8
 
8
 public class NavigationOptions {
9
 public class NavigationOptions {
9
 
10
 
11
+	private static final String NO_VALUE = "";
12
+	private static final int NO_INT_VALUE = Integer.MIN_VALUE;
13
+	private static final float NO_FLOAT_VALUE = Float.MIN_VALUE;
14
+	private static final int NO_COLOR_VALUE = Color.TRANSPARENT;
15
+
16
+	public enum BooleanOptions {
17
+		True,
18
+		False,
19
+		NoValue;
20
+
21
+		static BooleanOptions parse(String value) {
22
+			if (value != null && !value.equals("")) {
23
+				return Boolean.valueOf(value) ? True : False;
24
+			}
25
+			return NoValue;
26
+		}
27
+	}
28
+
10
 	@NonNull
29
 	@NonNull
11
 	public static NavigationOptions parse(JSONObject json) {
30
 	public static NavigationOptions parse(JSONObject json) {
12
 		NavigationOptions result = new NavigationOptions();
31
 		NavigationOptions result = new NavigationOptions();
13
 		if (json == null) return result;
32
 		if (json == null) return result;
14
 
33
 
15
-		result.title = json.optString("title");
16
-		result.topBarBackgroundColor = json.optInt("topBarBackgroundColor");
17
-		result.topBarTextColor = json.optInt("topBarTextColor");
18
-		result.topBarTextFontSize = (float) json.optDouble("topBarTextFontSize");
19
-		result.topBarTextFontFamily = json.optString("topBarTextFontFamily");
34
+		result.title = json.optString("title", NO_VALUE);
35
+		result.topBarBackgroundColor = json.optInt("topBarBackgroundColor", NO_COLOR_VALUE);
36
+		result.topBarTextColor = json.optInt("topBarTextColor", NO_INT_VALUE);
37
+		result.topBarTextFontSize = (float) json.optDouble("topBarTextFontSize", NO_FLOAT_VALUE);
38
+		result.topBarTextFontFamily = json.optString("topBarTextFontFamily", NO_VALUE);
39
+		result.topBarHidden = BooleanOptions.parse(json.optString("topBarHidden"));
40
+		result.animateTopBarHide = BooleanOptions.parse(json.optString("animateTopBarHide"));
20
 
41
 
21
 		return result;
42
 		return result;
22
 	}
43
 	}
23
 
44
 
24
 	public String title = "";
45
 	public String title = "";
25
-	public int topBarBackgroundColor = 0;
46
+	@ColorInt
47
+	public int topBarBackgroundColor;
26
 	@ColorInt
48
 	@ColorInt
27
 	public int topBarTextColor;
49
 	public int topBarTextColor;
28
 	public float topBarTextFontSize;
50
 	public float topBarTextFontSize;
29
 	public String topBarTextFontFamily;
51
 	public String topBarTextFontFamily;
52
+	public BooleanOptions topBarHidden = BooleanOptions.False;
53
+	public BooleanOptions animateTopBarHide = BooleanOptions.False;
30
 
54
 
31
 	public void mergeWith(final NavigationOptions other) {
55
 	public void mergeWith(final NavigationOptions other) {
32
-		title = other.title;
33
-		topBarBackgroundColor = other.topBarBackgroundColor;
34
-		topBarTextColor = other.topBarTextColor;
35
-		topBarTextFontSize = other.topBarTextFontSize;
36
-		topBarTextFontFamily = other.topBarTextFontFamily;
56
+		if (!NO_VALUE.equals(other.title)) title = other.title;
57
+		if (other.topBarBackgroundColor != NO_COLOR_VALUE)
58
+			topBarBackgroundColor = other.topBarBackgroundColor;
59
+		if (other.topBarTextColor != NO_INT_VALUE)
60
+			topBarTextColor = other.topBarTextColor;
61
+		if (other.topBarTextFontSize != NO_FLOAT_VALUE)
62
+			topBarTextFontSize = other.topBarTextFontSize;
63
+		if (!NO_VALUE.equals(other.topBarTextFontFamily))
64
+			topBarTextFontFamily = other.topBarTextFontFamily;
65
+		if (other.topBarHidden != BooleanOptions.NoValue) {
66
+			topBarHidden = other.topBarHidden;
67
+		}
68
+		if (other.animateTopBarHide != BooleanOptions.NoValue) {
69
+			animateTopBarHide = other.animateTopBarHide;
70
+		}
37
 	}
71
 	}
38
 }
72
 }

+ 45
- 8
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
+import android.util.Log;
4
+import android.view.View;
5
+
6
+import com.reactnativenavigation.anim.StackAnimator;
3
 import com.reactnativenavigation.parse.NavigationOptions;
7
 import com.reactnativenavigation.parse.NavigationOptions;
4
 import com.reactnativenavigation.utils.TypefaceLoader;
8
 import com.reactnativenavigation.utils.TypefaceLoader;
5
-import com.reactnativenavigation.viewcontrollers.StackController;
6
-
7
-/**
8
- * Created by romanko on 9/14/17.
9
- */
9
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
10
+import com.reactnativenavigation.views.TopbarContainerView;
10
 
11
 
11
 public class OptionsPresenter {
12
 public class OptionsPresenter {
12
 
13
 
13
-	private StackController controller;
14
+	private ContainerViewController controller;
15
+	private final StackAnimator animator;
14
 
16
 
15
-	public OptionsPresenter(StackController controller) {
17
+	public OptionsPresenter(ContainerViewController controller) {
16
 		this.controller = controller;
18
 		this.controller = controller;
19
+		animator = new StackAnimator(controller.getActivity());
17
 	}
20
 	}
18
 
21
 
19
 	public void applyOptions(NavigationOptions options) {
22
 	public void applyOptions(NavigationOptions options) {
20
-		if (controller != null) {
23
+		if (controller != null && controller.getTopBar() != null) {
21
 			controller.getTopBar().setTitle(options.title);
24
 			controller.getTopBar().setTitle(options.title);
22
 			controller.getTopBar().setBackgroundColor(options.topBarBackgroundColor);
25
 			controller.getTopBar().setBackgroundColor(options.topBarBackgroundColor);
23
 			controller.getTopBar().setTitleTextColor(options.topBarTextColor);
26
 			controller.getTopBar().setTitleTextColor(options.topBarTextColor);
24
 			controller.getTopBar().setTitleFontSize(options.topBarTextFontSize);
27
 			controller.getTopBar().setTitleFontSize(options.topBarTextFontSize);
25
 			TypefaceLoader typefaceLoader = new TypefaceLoader();
28
 			TypefaceLoader typefaceLoader = new TypefaceLoader();
26
 			controller.getTopBar().setTitleTypeface(typefaceLoader.getTypeFace(controller.getActivity(), options.topBarTextFontFamily));
29
 			controller.getTopBar().setTitleTypeface(typefaceLoader.getTypeFace(controller.getActivity(), options.topBarTextFontFamily));
30
+			applyTopbarHiddenOptions(options);
31
+		}
32
+	}
33
+
34
+	private void applyTopbarHiddenOptions(NavigationOptions options) {
35
+		if (options.topBarHidden == NavigationOptions.BooleanOptions.True) {
36
+			hideTopbar(options.animateTopBarHide);
37
+		}
38
+		if (options.topBarHidden == NavigationOptions.BooleanOptions.False) {
39
+			showTopbar(options.animateTopBarHide);
40
+		}
41
+	}
42
+
43
+	private void showTopbar(NavigationOptions.BooleanOptions animated) {
44
+		if (controller.getTopBar().getVisibility() == View.VISIBLE) {
45
+			return;
46
+		}
47
+		if (animated == NavigationOptions.BooleanOptions.True) {
48
+			TopbarContainerView topbarContainerView = (TopbarContainerView) controller.getContainerView();
49
+			animator.animateShowTopBar(controller.getTopBar(), topbarContainerView.getContainerView().asView());
50
+		} else {
51
+			controller.getTopBar().setVisibility(View.VISIBLE);
52
+		}
53
+	}
54
+
55
+	private void hideTopbar(NavigationOptions.BooleanOptions animated) {
56
+		if (controller.getTopBar().getVisibility() == View.GONE) {
57
+			return;
58
+		}
59
+		if (animated == NavigationOptions.BooleanOptions.True) {
60
+			TopbarContainerView topbarContainerView = (TopbarContainerView) controller.getContainerView();
61
+			animator.animateHideTopBar(controller.getTopBar(), topbarContainerView.getContainerView().asView());
62
+		} else {
63
+			controller.getTopBar().setVisibility(View.GONE);
27
 		}
64
 		}
28
 	}
65
 	}
29
 }
66
 }

+ 2
- 0
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java View File

17
 import com.reactnativenavigation.viewcontrollers.Navigator;
17
 import com.reactnativenavigation.viewcontrollers.Navigator;
18
 import com.reactnativenavigation.viewcontrollers.ViewController;
18
 import com.reactnativenavigation.viewcontrollers.ViewController;
19
 
19
 
20
+import org.json.JSONObject;
21
+
20
 public class NavigationModule extends ReactContextBaseJavaModule {
22
 public class NavigationModule extends ReactContextBaseJavaModule {
21
 	private static final String NAME = "RNNBridgeModule";
23
 	private static final String NAME = "RNNBridgeModule";
22
 	private final ReactInstanceManager reactInstanceManager;
24
 	private final ReactInstanceManager reactInstanceManager;

+ 21
- 4
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ContainerViewController.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
+import android.util.Log;
5
 import android.view.View;
6
 import android.view.View;
6
 
7
 
8
+import com.reactnativenavigation.anim.StackAnimator;
7
 import com.reactnativenavigation.parse.NavigationOptions;
9
 import com.reactnativenavigation.parse.NavigationOptions;
8
 import com.reactnativenavigation.presentation.OptionsPresenter;
10
 import com.reactnativenavigation.presentation.OptionsPresenter;
11
+import com.reactnativenavigation.views.TopBar;
12
+import com.reactnativenavigation.views.TopbarContainerView;
9
 
13
 
10
 public class ContainerViewController extends ViewController {
14
 public class ContainerViewController extends ViewController {
11
 
15
 
31
 	private final String containerName;
35
 	private final String containerName;
32
 
36
 
33
 	private final ContainerViewCreator viewCreator;
37
 	private final ContainerViewCreator viewCreator;
34
-	private final NavigationOptions navigationOptions;
38
+	private NavigationOptions navigationOptions;
35
 	private ContainerView containerView;
39
 	private ContainerView containerView;
36
 
40
 
41
+	private TopBar topBar;
42
+
37
 	public ContainerViewController(final Activity activity,
43
 	public ContainerViewController(final Activity activity,
38
 								   final String id,
44
 								   final String id,
39
 								   final String containerName,
45
 								   final String containerName,
75
 	@Override
81
 	@Override
76
 	protected View createView() {
82
 	protected View createView() {
77
 		containerView = viewCreator.create(getActivity(), getId(), containerName);
83
 		containerView = viewCreator.create(getActivity(), getId(), containerName);
84
+		if (containerView instanceof TopbarContainerView) {
85
+			topBar = ((TopbarContainerView) containerView).getTopBar();
86
+		}
78
 		return containerView.asView();
87
 		return containerView.asView();
79
 	}
88
 	}
80
 
89
 
81
-	public void mergeNavigationOptions(final NavigationOptions options) {
90
+	void mergeNavigationOptions(NavigationOptions options) {
82
 		navigationOptions.mergeWith(options);
91
 		navigationOptions.mergeWith(options);
83
 		applyOptions();
92
 		applyOptions();
84
 	}
93
 	}
85
 
94
 
86
-	public NavigationOptions getNavigationOptions() {
95
+	NavigationOptions getNavigationOptions() {
87
 		return navigationOptions;
96
 		return navigationOptions;
88
 	}
97
 	}
89
 
98
 
90
 	private void applyOptions() {
99
 	private void applyOptions() {
91
-		OptionsPresenter presenter = new OptionsPresenter(getParentStackController());
100
+		OptionsPresenter presenter = new OptionsPresenter(this);
92
 		presenter.applyOptions(navigationOptions);
101
 		presenter.applyOptions(navigationOptions);
93
 	}
102
 	}
103
+
104
+	public TopBar getTopBar() {
105
+		return topBar;
106
+	}
107
+
108
+	public ContainerView getContainerView() {
109
+		return containerView;
110
+	}
94
 }
111
 }

+ 2
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java View File

8
 import com.reactnativenavigation.parse.NavigationOptions;
8
 import com.reactnativenavigation.parse.NavigationOptions;
9
 import com.reactnativenavigation.utils.CompatUtils;
9
 import com.reactnativenavigation.utils.CompatUtils;
10
 
10
 
11
+import org.json.JSONObject;
12
+
11
 import java.util.Collection;
13
 import java.util.Collection;
12
 import java.util.Collections;
14
 import java.util.Collections;
13
 
15
 

+ 10
- 32
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.animation.Animator;
4
 import android.app.Activity;
3
 import android.app.Activity;
5
 import android.graphics.Color;
4
 import android.graphics.Color;
6
-import android.os.Handler;
7
-import android.os.Looper;
8
 import android.support.annotation.NonNull;
5
 import android.support.annotation.NonNull;
6
+import android.util.Log;
9
 import android.view.View;
7
 import android.view.View;
10
 import android.view.ViewGroup;
8
 import android.view.ViewGroup;
11
 import android.widget.FrameLayout;
9
 import android.widget.FrameLayout;
12
 import android.widget.LinearLayout;
10
 import android.widget.LinearLayout;
11
+import android.widget.RelativeLayout;
13
 
12
 
14
 import com.reactnativenavigation.anim.StackAnimator;
13
 import com.reactnativenavigation.anim.StackAnimator;
15
-import com.reactnativenavigation.react.ReactContainerView;
16
 import com.reactnativenavigation.utils.CompatUtils;
14
 import com.reactnativenavigation.utils.CompatUtils;
17
 import com.reactnativenavigation.views.TopBar;
15
 import com.reactnativenavigation.views.TopBar;
18
 
16
 
19
 import java.util.Collection;
17
 import java.util.Collection;
20
-import java.util.Random;
18
+
19
+import static android.widget.RelativeLayout.BELOW;
21
 
20
 
22
 public class StackController extends ParentController {
21
 public class StackController extends ParentController {
23
 
22
 
24
 	private final IdStack<ViewController> stack = new IdStack<>();
23
 	private final IdStack<ViewController> stack = new IdStack<>();
25
 	private final StackAnimator animator;
24
 	private final StackAnimator animator;
26
-	private TopBar topBar;
27
-	private FrameLayout container;
28
 
25
 
29
 	public StackController(final Activity activity, String id) {
26
 	public StackController(final Activity activity, String id) {
30
 		this(activity, id, new StackAnimator(activity));
27
 		this(activity, id, new StackAnimator(activity));
41
 		child.setParentStackController(this);
38
 		child.setParentStackController(this);
42
 		stack.push(child.getId(), child);
39
 		stack.push(child.getId(), child);
43
 		View enteringView = child.getView();
40
 		View enteringView = child.getView();
44
-		getContainer().addView(enteringView);
41
+		getView().addView(enteringView);
45
 
42
 
46
 		//TODO animatePush only when needed
43
 		//TODO animatePush only when needed
47
 		if (previousTop != null) {
44
 		if (previousTop != null) {
48
 			animator.animatePush(enteringView, new StackAnimator.StackAnimationListener() {
45
 			animator.animatePush(enteringView, new StackAnimator.StackAnimationListener() {
49
 				@Override
46
 				@Override
50
 				public void onAnimationEnd() {
47
 				public void onAnimationEnd() {
51
-					getContainer().removeView(previousTop.getView());
48
+					getView().removeView(previousTop.getView());
52
 				}
49
 				}
53
 			});
50
 			});
51
+
54
 		}
52
 		}
55
 	}
53
 	}
56
 
54
 
66
 
64
 
67
 		View enteringView = newTop.getView();
65
 		View enteringView = newTop.getView();
68
 		final View exitingView = poppedTop.getView();
66
 		final View exitingView = poppedTop.getView();
69
-		getContainer().addView(enteringView, getContainer().getChildCount() - 1);
67
+		getView().addView(enteringView, getView().getChildCount() - 1);
70
 
68
 
71
 		//TODO animatePush only when needed
69
 		//TODO animatePush only when needed
72
 		animator.animatePop(exitingView, new StackAnimator.StackAnimationListener() {
70
 		animator.animatePop(exitingView, new StackAnimator.StackAnimationListener() {
73
 			@Override
71
 			@Override
74
 			public void onAnimationEnd() {
72
 			public void onAnimationEnd() {
75
-				getContainer().removeView(exitingView);
73
+				getView().removeView(exitingView);
76
 				poppedTop.destroy();
74
 				poppedTop.destroy();
77
 			}
75
 			}
78
 		});
76
 		});
127
 	@NonNull
125
 	@NonNull
128
 	@Override
126
 	@Override
129
 	protected ViewGroup createView() {
127
 	protected ViewGroup createView() {
130
-		LinearLayout root = new LinearLayout(getActivity());
131
-		root.setOrientation(LinearLayout.VERTICAL);
132
-		topBar = new TopBar(getActivity());
133
-		topBar.setId(CompatUtils.generateViewId());
134
-		root.addView(topBar);
135
-		container = new FrameLayout(getActivity());
136
-		container.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
137
-		root.addView(container);
138
-		return root;
128
+		return new FrameLayout(getActivity());
139
 	}
129
 	}
140
 
130
 
141
 	@NonNull
131
 	@NonNull
143
 	public Collection<ViewController> getChildControllers() {
133
 	public Collection<ViewController> getChildControllers() {
144
 		return stack.values();
134
 		return stack.values();
145
 	}
135
 	}
146
-
147
-	public TopBar getTopBar() {
148
-		ensureViewIsCreated();
149
-		return topBar;
150
-	}
151
-
152
-	private ViewGroup getContainer() {
153
-		if (container == null) {
154
-			getView();
155
-		}
156
-		return container;
157
-	}
158
 }
136
 }

+ 12
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
+import android.content.Context;
4
 import android.graphics.Typeface;
5
 import android.graphics.Typeface;
5
 import android.support.annotation.ColorInt;
6
 import android.support.annotation.ColorInt;
6
 import android.support.annotation.Nullable;
7
 import android.support.annotation.Nullable;
13
 public class TopBar extends AppBarLayout {
14
 public class TopBar extends AppBarLayout {
14
 	private final Toolbar titleBar;
15
 	private final Toolbar titleBar;
15
 
16
 
16
-	public TopBar(final Activity context) {
17
+	public TopBar(final Context context) {
17
 		super(context);
18
 		super(context);
18
 		titleBar = new Toolbar(context);
19
 		titleBar = new Toolbar(context);
19
 		addView(titleBar);
20
 		addView(titleBar);
49
 		return findTextView(titleBar);
50
 		return findTextView(titleBar);
50
 	}
51
 	}
51
 
52
 
53
+	@Override
54
+	public void setBackgroundColor(@ColorInt int color) {
55
+		titleBar.setBackgroundColor(color);
56
+	}
57
+
52
 	@Nullable
58
 	@Nullable
53
-	public TextView findTextView(ViewGroup root) {
59
+	private TextView findTextView(ViewGroup root) {
54
 		for (int i = 0; i < root.getChildCount(); i++) {
60
 		for (int i = 0; i < root.getChildCount(); i++) {
55
 			View view = root.getChildAt(i);
61
 			View view = root.getChildAt(i);
56
 			if (view instanceof TextView) {
62
 			if (view instanceof TextView) {
62
 		}
68
 		}
63
 		return null;
69
 		return null;
64
 	}
70
 	}
71
+
72
+	public Toolbar getTitleBar() {
73
+		return titleBar;
74
+	}
65
 }
75
 }

+ 65
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/TopbarContainerView.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.view.View;
5
+import android.view.ViewGroup;
6
+import android.widget.LinearLayout;
7
+
8
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
9
+
10
+public class TopbarContainerView extends LinearLayout implements ContainerViewController.ContainerView {
11
+
12
+	private TopBar topBar;
13
+	private ContainerViewController.ContainerView containerView;
14
+
15
+	public TopbarContainerView(Context context, ContainerViewController.ContainerView containerView) {
16
+		super(context);
17
+		this.topBar = new TopBar(context);
18
+		this.containerView = containerView;
19
+
20
+		initViews();
21
+	}
22
+
23
+	private void initViews() {
24
+		setOrientation(LinearLayout.VERTICAL);
25
+		addView(topBar);
26
+		addView(containerView.asView());
27
+	}
28
+
29
+	public TopbarContainerView(Context context) {
30
+		super(context);
31
+	}
32
+
33
+	@Override
34
+	public boolean isReady() {
35
+		return containerView.isReady();
36
+	}
37
+
38
+	@Override
39
+	public View asView() {
40
+		return this;
41
+	}
42
+
43
+	@Override
44
+	public void destroy() {
45
+		containerView.destroy();
46
+	}
47
+
48
+	@Override
49
+	public void sendContainerStart() {
50
+		containerView.sendContainerStart();
51
+	}
52
+
53
+	@Override
54
+	public void sendContainerStop() {
55
+		containerView.sendContainerStop();
56
+	}
57
+
58
+	public TopBar getTopBar() {
59
+		return topBar;
60
+	}
61
+
62
+	public ContainerViewController.ContainerView getContainerView() {
63
+		return containerView;
64
+	}
65
+}

+ 23
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/TopbarContainerViewCreator.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import android.app.Activity;
4
+
5
+import com.reactnativenavigation.viewcontrollers.ContainerViewController;
6
+
7
+public class TopbarContainerViewCreator implements ContainerViewController.ContainerViewCreator {
8
+
9
+	private ContainerViewController.ContainerViewCreator creator;
10
+
11
+	public TopbarContainerViewCreator(ContainerViewController.ContainerViewCreator creator) {
12
+		this.creator = creator;
13
+	}
14
+
15
+	@Override
16
+	public ContainerViewController.ContainerView create(Activity activity, String containerId, String containerName) {
17
+		ContainerViewController.ContainerView containerView = creator.create(activity, containerId, containerName);
18
+
19
+		TopbarContainerView root = new TopbarContainerView(activity, containerView);
20
+		return root;
21
+
22
+	}
23
+}

+ 2
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleContainerViewController.java View File

4
 
4
 
5
 import com.reactnativenavigation.parse.NavigationOptions;
5
 import com.reactnativenavigation.parse.NavigationOptions;
6
 import com.reactnativenavigation.viewcontrollers.ContainerViewController;
6
 import com.reactnativenavigation.viewcontrollers.ContainerViewController;
7
+import com.reactnativenavigation.views.TopbarContainerViewCreator;
7
 
8
 
8
 public class SimpleContainerViewController extends ContainerViewController {
9
 public class SimpleContainerViewController extends ContainerViewController {
9
 	public SimpleContainerViewController(final Activity activity, final String id) {
10
 	public SimpleContainerViewController(final Activity activity, final String id) {
10
-		super(activity, id, "theContainerName", new TestContainerViewCreator(), new NavigationOptions());
11
+		super(activity, id, "theContainerName", new TopbarContainerViewCreator(new TestContainerViewCreator()), new NavigationOptions());
11
 	}
12
 	}
12
 }
13
 }

+ 7
- 0
lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestContainerView.java View File

2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.view.View;
4
 import android.view.View;
5
+import android.view.ViewGroup;
5
 
6
 
6
 import com.reactnativenavigation.viewcontrollers.ContainerViewController;
7
 import com.reactnativenavigation.viewcontrollers.ContainerViewController;
8
+import com.reactnativenavigation.views.TopBar;
7
 
9
 
8
 public class TestContainerView extends View implements ContainerViewController.ContainerView {
10
 public class TestContainerView extends View implements ContainerViewController.ContainerView {
11
+
12
+	private TopBar topBar;
13
+
9
 	public TestContainerView(final Context context) {
14
 	public TestContainerView(final Context context) {
10
 		super(context);
15
 		super(context);
16
+		topBar = new TopBar(context);
17
+
11
 	}
18
 	}
12
 
19
 
13
 	@Override
20
 	@Override

+ 3
- 0
lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java View File

5
 import org.json.JSONObject;
5
 import org.json.JSONObject;
6
 import org.junit.Test;
6
 import org.junit.Test;
7
 
7
 
8
+import static com.reactnativenavigation.parse.NavigationOptions.BooleanOptions.True;
8
 import static org.assertj.core.api.Java6Assertions.assertThat;
9
 import static org.assertj.core.api.Java6Assertions.assertThat;
9
 
10
 
10
 public class NavigationOptionsTest extends BaseTest {
11
 public class NavigationOptionsTest extends BaseTest {
22
 		json.put("topBarTextColor", 0xff123456);
23
 		json.put("topBarTextColor", 0xff123456);
23
 		json.put("topBarTextFontSize", 18);
24
 		json.put("topBarTextFontSize", 18);
24
 		json.put("topBarTextFontFamily", "HelveticaNeue-CondensedBold");
25
 		json.put("topBarTextFontFamily", "HelveticaNeue-CondensedBold");
26
+		json.put("topBarHidden", true);
25
 
27
 
26
 		NavigationOptions result = NavigationOptions.parse(json);
28
 		NavigationOptions result = NavigationOptions.parse(json);
27
 		assertThat(result.title).isEqualTo("the title");
29
 		assertThat(result.title).isEqualTo("the title");
29
 		assertThat(result.topBarTextColor).isEqualTo(0xff123456);
31
 		assertThat(result.topBarTextColor).isEqualTo(0xff123456);
30
 		assertThat(result.topBarTextFontSize).isEqualTo(18);
32
 		assertThat(result.topBarTextFontSize).isEqualTo(18);
31
 		assertThat(result.topBarTextFontFamily).isEqualTo("HelveticaNeue-CondensedBold");
33
 		assertThat(result.topBarTextFontFamily).isEqualTo("HelveticaNeue-CondensedBold");
34
+		assertThat(result.topBarHidden).isEqualTo(True);
32
 	}
35
 	}
33
 
36
 
34
 	@Test
37
 	@Test

+ 0
- 15
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java View File

207
 		uut.setOptions("some unknown child id", new NavigationOptions());
207
 		uut.setOptions("some unknown child id", new NavigationOptions());
208
 	}
208
 	}
209
 
209
 
210
-	@Test
211
-	public void setOptions_ActuallyAffectsTheTitleView() throws Exception {
212
-		ContainerViewController containerVc = new SimpleContainerViewController(activity, "theId");
213
-		StackController stackController = new StackController(activity, "stackId", new TestStackAnimator());
214
-		stackController.push(containerVc);
215
-		uut.setRoot(stackController);
216
-		assertThat(stackController.getTopBar().getTitle()).isEmpty();
217
-
218
-		NavigationOptions opts = new NavigationOptions();
219
-		opts.title = "the new title";
220
-		uut.setOptions("theId", opts);
221
-
222
-		assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
223
-	}
224
-
225
 	@NonNull
210
 	@NonNull
226
 	private BottomTabsController newTabs() {
211
 	private BottomTabsController newTabs() {
227
 		return new BottomTabsController(activity, "tabsController");
212
 		return new BottomTabsController(activity, "tabsController");

+ 39
- 26
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.graphics.Color;
4
 import android.graphics.Color;
5
 import android.graphics.drawable.ColorDrawable;
5
 import android.graphics.drawable.ColorDrawable;
6
+import android.view.View;
6
 
7
 
7
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.BaseTest;
8
 import com.reactnativenavigation.mocks.TestContainerView;
9
 import com.reactnativenavigation.mocks.TestContainerView;
9
 import com.reactnativenavigation.parse.NavigationOptions;
10
 import com.reactnativenavigation.parse.NavigationOptions;
11
+import com.reactnativenavigation.views.TopbarContainerViewCreator;
10
 
12
 
13
+import org.json.JSONObject;
11
 import org.junit.Test;
14
 import org.junit.Test;
12
 
15
 
13
 import static org.assertj.core.api.Java6Assertions.assertThat;
16
 import static org.assertj.core.api.Java6Assertions.assertThat;
28
 		activity = newActivity();
31
 		activity = newActivity();
29
 		initialNavigationOptions = new NavigationOptions();
32
 		initialNavigationOptions = new NavigationOptions();
30
 		view = spy(new TestContainerView(activity));
33
 		view = spy(new TestContainerView(activity));
31
-		uut = new ContainerViewController(activity, "containerId1", "containerName", new ContainerViewController.ContainerViewCreator() {
32
-			@Override
33
-			public ContainerViewController.ContainerView create(final Activity activity1, final String containerId, final String containerName) {
34
-				return view;
35
-			}
36
-		}, initialNavigationOptions);
34
+		uut = new ContainerViewController(activity, "containerId1", "containerName",
35
+				new TopbarContainerViewCreator(new ContainerViewController.ContainerViewCreator() {
36
+					@Override
37
+					public ContainerViewController.ContainerView create(final Activity activity1, final String containerId, final String containerName) {
38
+						return view;
39
+					}
40
+				}), initialNavigationOptions);
37
 	}
41
 	}
38
 
42
 
39
 	@Test
43
 	@Test
49
 		initialNavigationOptions.title = "the title";
53
 		initialNavigationOptions.title = "the title";
50
 		StackController stackController = new StackController(activity, "stackId");
54
 		StackController stackController = new StackController(activity, "stackId");
51
 		stackController.push(uut);
55
 		stackController.push(uut);
52
-		assertThat(stackController.getTopBar().getTitle()).isEmpty();
56
+		assertThat(uut.getTopBar().getTitle()).isEmpty();
53
 
57
 
54
 		uut.onViewAppeared();
58
 		uut.onViewAppeared();
55
-		assertThat(stackController.getTopBar().getTitle()).isEqualTo("the title");
59
+		assertThat(uut.getTopBar().getTitle()).isEqualTo("the title");
56
 	}
60
 	}
57
 
61
 
58
 	@Test
62
 	@Test
67
 
71
 
68
 	@Test
72
 	@Test
69
 	public void reappliesOptionsOnMerge() throws Exception {
73
 	public void reappliesOptionsOnMerge() throws Exception {
70
-		StackController stackController = new StackController(activity, "stackId");
71
-		stackController.push(uut);
72
-		assertThat(stackController.getTopBar().getTitle()).isEmpty();
74
+		uut.onViewAppeared();
75
+		assertThat(uut.getTopBar().getTitle()).isEmpty();
73
 
76
 
74
 		NavigationOptions opts = new NavigationOptions();
77
 		NavigationOptions opts = new NavigationOptions();
75
 		opts.title = "the new title";
78
 		opts.title = "the new title";
76
 		uut.mergeNavigationOptions(opts);
79
 		uut.mergeNavigationOptions(opts);
77
 
80
 
78
-		assertThat(stackController.getTopBar().getTitle()).isEqualTo("the new title");
81
+		assertThat(uut.getTopBar().getTitle()).isEqualTo("the new title");
79
 	}
82
 	}
80
 
83
 
81
 	@Test
84
 	@Test
82
 	public void appliesTopBackBackgroundColor() throws Exception {
85
 	public void appliesTopBackBackgroundColor() throws Exception {
83
-		StackController stackController = new StackController(activity, "stackId");
84
-		stackController.push(uut);
85
-		assertThat(((ColorDrawable) stackController.getTopBar().getBackground()).getColor()).isNotEqualTo(Color.RED);
86
+		uut.onViewAppeared();
87
+		//TODO: FIX TEST
88
+		assertThat(((ColorDrawable) uut.getTopBar().getTitleBar().getBackground()).getColor()).isNotEqualTo(Color.RED);
86
 
89
 
87
 		NavigationOptions opts = new NavigationOptions();
90
 		NavigationOptions opts = new NavigationOptions();
88
 		opts.topBarBackgroundColor = Color.RED;
91
 		opts.topBarBackgroundColor = Color.RED;
89
 		uut.mergeNavigationOptions(opts);
92
 		uut.mergeNavigationOptions(opts);
90
 
93
 
91
-		assertThat(((ColorDrawable) stackController.getTopBar().getBackground()).getColor()).isEqualTo(Color.RED);
94
+		assertThat(((ColorDrawable) uut.getTopBar().getTitleBar().getBackground()).getColor()).isEqualTo(Color.RED);
92
 	}
95
 	}
93
 
96
 
94
 	@Test
97
 	@Test
95
 	public void appliesTopBarTextColor() throws Exception {
98
 	public void appliesTopBarTextColor() throws Exception {
96
 		assertThat(uut.getNavigationOptions()).isSameAs(initialNavigationOptions);
99
 		assertThat(uut.getNavigationOptions()).isSameAs(initialNavigationOptions);
97
 		initialNavigationOptions.title = "the title";
100
 		initialNavigationOptions.title = "the title";
98
-		StackController stackController = new StackController(activity, "stackId");
99
-		stackController.push(uut);
100
 		uut.onViewAppeared();
101
 		uut.onViewAppeared();
101
-		assertThat(stackController.getTopBar().getTitleTextView().getCurrentTextColor()).isNotEqualTo(Color.RED);
102
+		assertThat(uut.getTopBar().getTitleTextView().getCurrentTextColor()).isNotEqualTo(Color.RED);
102
 
103
 
103
 		NavigationOptions opts = new NavigationOptions();
104
 		NavigationOptions opts = new NavigationOptions();
104
 		opts.title = "the title";
105
 		opts.title = "the title";
105
 		opts.topBarTextColor = Color.RED;
106
 		opts.topBarTextColor = Color.RED;
106
 		uut.mergeNavigationOptions(opts);
107
 		uut.mergeNavigationOptions(opts);
107
 
108
 
108
-		assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
109
-		assertThat(stackController.getTopBar().getTitleTextView().getCurrentTextColor()).isEqualTo(Color.RED);
109
+		assertThat(uut.getTopBar().getTitleTextView()).isNotEqualTo(null);
110
+		assertThat(uut.getTopBar().getTitleTextView().getCurrentTextColor()).isEqualTo(Color.RED);
110
 	}
111
 	}
111
 
112
 
112
 	@Test
113
 	@Test
113
 	public void appliesTopBarTextSize() throws Exception {
114
 	public void appliesTopBarTextSize() throws Exception {
114
 		assertThat(uut.getNavigationOptions()).isSameAs(initialNavigationOptions);
115
 		assertThat(uut.getNavigationOptions()).isSameAs(initialNavigationOptions);
115
 		initialNavigationOptions.title = "the title";
116
 		initialNavigationOptions.title = "the title";
116
-		StackController stackController = new StackController(activity, "stackId");
117
-		stackController.push(uut);
118
 		uut.onViewAppeared();
117
 		uut.onViewAppeared();
119
-		assertThat(stackController.getTopBar().getTitleTextView().getTextSize()).isNotEqualTo(18);
118
+		assertThat(uut.getTopBar().getTitleTextView().getTextSize()).isNotEqualTo(18);
120
 
119
 
121
 		NavigationOptions opts = new NavigationOptions();
120
 		NavigationOptions opts = new NavigationOptions();
122
 		opts.title = "the title";
121
 		opts.title = "the title";
123
 		opts.topBarTextFontSize = 18;
122
 		opts.topBarTextFontSize = 18;
124
 		uut.mergeNavigationOptions(opts);
123
 		uut.mergeNavigationOptions(opts);
125
 
124
 
126
-		assertThat(stackController.getTopBar().getTitleTextView()).isNotEqualTo(null);
127
-		assertThat(stackController.getTopBar().getTitleTextView().getTextSize()).isEqualTo(18);
125
+		assertThat(uut.getTopBar().getTitleTextView()).isNotEqualTo(null);
126
+		assertThat(uut.getTopBar().getTitleTextView().getTextSize()).isEqualTo(18);
127
+	}
128
+
129
+	@Test
130
+	public void appliesTopBarHidden() throws Exception {
131
+		assertThat(uut.getNavigationOptions()).isSameAs(initialNavigationOptions);
132
+		initialNavigationOptions.title = "the title";
133
+		uut.onViewAppeared();
134
+		assertThat(uut.getTopBar().getVisibility()).isNotEqualTo(View.GONE);
135
+
136
+		NavigationOptions opts = new NavigationOptions();
137
+		opts.topBarHidden = NavigationOptions.BooleanOptions.True;
138
+		uut.mergeNavigationOptions(opts);
139
+
140
+		assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.GONE);
128
 	}
141
 	}
129
 }
142
 }

+ 1
- 0
lib/ios/RNNNavigationOptions.h View File

26
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
26
 @property (nonatomic, strong) NSNumber* statusBarHideWithTopBar;
27
 @property (nonatomic, strong) NSNumber* tabBarHidden;
27
 @property (nonatomic, strong) NSNumber* tabBarHidden;
28
 @property (nonatomic, strong) NSNumber* topBarBlur;
28
 @property (nonatomic, strong) NSNumber* topBarBlur;
29
+@property (nonatomic, strong) NSNumber* animateTopBarHide;
29
 
30
 
30
 
31
 
31
 - (UIInterfaceOrientationMask)supportedOrientations;
32
 - (UIInterfaceOrientationMask)supportedOrientations;

+ 17
- 20
lib/ios/RNNNavigationOptions.m View File

32
 	self.topBarNoBorder = [navigationOptions objectForKey:@"topBarNoBorder"];
32
 	self.topBarNoBorder = [navigationOptions objectForKey:@"topBarNoBorder"];
33
 	self.tabBarHidden = [navigationOptions objectForKey:@"tabBarHidden"];
33
 	self.tabBarHidden = [navigationOptions objectForKey:@"tabBarHidden"];
34
 	self.topBarBlur = [navigationOptions objectForKey:@"topBarBlur"];
34
 	self.topBarBlur = [navigationOptions objectForKey:@"topBarBlur"];
35
+	self.animateTopBarHide = [navigationOptions objectForKey:@"animateTopBarHide"];
35
 
36
 
36
 	return self;
37
 	return self;
37
 }
38
 }
49
 	} else {
50
 	} else {
50
 		viewController.navigationController.navigationBar.barTintColor = nil;
51
 		viewController.navigationController.navigationBar.barTintColor = nil;
51
 	}
52
 	}
52
-	
53
+
53
 	if (self.title) {
54
 	if (self.title) {
54
 		viewController.navigationItem.title = self.title;
55
 		viewController.navigationItem.title = self.title;
55
 	}
56
 	}
56
-	
57
+
57
 	if (self.topBarTextFontFamily || self.topBarTextColor || self.topBarTextFontSize){
58
 	if (self.topBarTextFontFamily || self.topBarTextColor || self.topBarTextFontSize){
58
 		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
59
 		NSMutableDictionary* navigationBarTitleTextAttributes = [NSMutableDictionary new];
59
 		if (self.topBarTextColor) {
60
 		if (self.topBarTextColor) {
70
 		}
71
 		}
71
 		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
72
 		viewController.navigationController.navigationBar.titleTextAttributes = navigationBarTitleTextAttributes;
72
 	}
73
 	}
73
-	
74
+
74
 	if (self.screenBackgroundColor) {
75
 	if (self.screenBackgroundColor) {
75
 		UIColor* screenColor = [RCTConvert UIColor:self.screenBackgroundColor];
76
 		UIColor* screenColor = [RCTConvert UIColor:self.screenBackgroundColor];
76
 		viewController.view.backgroundColor = screenColor;
77
 		viewController.view.backgroundColor = screenColor;
77
 	}
78
 	}
78
-	
79
+
79
 	if (self.topBarHidden){
80
 	if (self.topBarHidden){
80
-		if ([self.topBarHidden boolValue]) {
81
-			[viewController.navigationController setNavigationBarHidden:YES animated:YES];
82
-		} else {
83
-			[viewController.navigationController setNavigationBarHidden:NO animated:YES];
84
-		}
81
+		[viewController.navigationController setNavigationBarHidden:[self.topBarHidden boolValue] animated:[self.animateTopBarHide boolValue]];
85
 	}
82
 	}
86
-	
83
+
87
 	if (self.topBarHideOnScroll) {
84
 	if (self.topBarHideOnScroll) {
88
 		BOOL topBarHideOnScrollBool = [self.topBarHideOnScroll boolValue];
85
 		BOOL topBarHideOnScrollBool = [self.topBarHideOnScroll boolValue];
89
 		if (topBarHideOnScrollBool) {
86
 		if (topBarHideOnScrollBool) {
92
 			viewController.navigationController.hidesBarsOnSwipe = NO;
89
 			viewController.navigationController.hidesBarsOnSwipe = NO;
93
 		}
90
 		}
94
 	}
91
 	}
95
-	
92
+
96
 	if (self.topBarButtonColor) {
93
 	if (self.topBarButtonColor) {
97
 		UIColor* buttonColor = [RCTConvert UIColor:self.topBarButtonColor];
94
 		UIColor* buttonColor = [RCTConvert UIColor:self.topBarButtonColor];
98
 		viewController.navigationController.navigationBar.tintColor = buttonColor;
95
 		viewController.navigationController.navigationBar.tintColor = buttonColor;
99
 	} else {
96
 	} else {
100
 		viewController.navigationController.navigationBar.tintColor = nil;
97
 		viewController.navigationController.navigationBar.tintColor = nil;
101
 	}
98
 	}
102
-	
99
+
103
 	if (self.tabBadge) {
100
 	if (self.tabBadge) {
104
 		NSString *badge = [RCTConvert NSString:self.tabBadge];
101
 		NSString *badge = [RCTConvert NSString:self.tabBadge];
105
 		if (viewController.navigationController) {
102
 		if (viewController.navigationController) {
108
 			viewController.tabBarItem.badgeValue = badge;
105
 			viewController.tabBarItem.badgeValue = badge;
109
 		}
106
 		}
110
 	}
107
 	}
111
-	
108
+
112
 	if (self.topBarTranslucent) {
109
 	if (self.topBarTranslucent) {
113
 		if ([self.topBarTranslucent boolValue]) {
110
 		if ([self.topBarTranslucent boolValue]) {
114
 			viewController.navigationController.navigationBar.translucent = YES;
111
 			viewController.navigationController.navigationBar.translucent = YES;
116
 			viewController.navigationController.navigationBar.translucent = NO;
113
 			viewController.navigationController.navigationBar.translucent = NO;
117
 		}
114
 		}
118
 	}
115
 	}
119
-	
116
+
120
 	if (self.topBarNoBorder) {
117
 	if (self.topBarNoBorder) {
121
 		if ([self.topBarNoBorder boolValue]) {
118
 		if ([self.topBarNoBorder boolValue]) {
122
 			viewController.navigationController.navigationBar
119
 			viewController.navigationController.navigationBar
126
 			.shadowImage = nil;
123
 			.shadowImage = nil;
127
 		}
124
 		}
128
 	}
125
 	}
129
-	
126
+
130
 	if (self.statusBarBlur) {
127
 	if (self.statusBarBlur) {
131
 		UIView* curBlurView = [viewController.view viewWithTag:BLUR_STATUS_TAG];
128
 		UIView* curBlurView = [viewController.view viewWithTag:BLUR_STATUS_TAG];
132
 		if ([self.statusBarBlur boolValue]) {
129
 		if ([self.statusBarBlur boolValue]) {
142
 			}
139
 			}
143
 		}
140
 		}
144
 	}
141
 	}
145
-	
142
+
146
 	if (self.topBarBlur && [self.topBarBlur boolValue]) {
143
 	if (self.topBarBlur && [self.topBarBlur boolValue]) {
147
-		
144
+
148
 		if (![viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]) {
145
 		if (![viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG]) {
149
-			
146
+
150
 			[viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
147
 			[viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
151
 			viewController.navigationController.navigationBar.shadowImage = [UIImage new];
148
 			viewController.navigationController.navigationBar.shadowImage = [UIImage new];
152
 			UIVisualEffectView *blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
149
 			UIVisualEffectView *blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
157
 			[viewController.navigationController.navigationBar insertSubview:blur atIndex:0];
154
 			[viewController.navigationController.navigationBar insertSubview:blur atIndex:0];
158
 			[viewController.navigationController.navigationBar sendSubviewToBack:blur];
155
 			[viewController.navigationController.navigationBar sendSubviewToBack:blur];
159
 		}
156
 		}
160
-		
157
+
161
 	} else {
158
 	} else {
162
 		UIView *blur = [viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG];
159
 		UIView *blur = [viewController.navigationController.navigationBar viewWithTag:BLUR_TOPBAR_TAG];
163
 		if (blur) {
160
 		if (blur) {
190
 			}
187
 			}
191
 		}
188
 		}
192
 	}
189
 	}
193
-	
190
+
194
 	return supportedOrientationsMask;
191
 	return supportedOrientationsMask;
195
 }
192
 }
196
 
193
 

+ 5
- 5
playground/src/containers/LifecycleScreen.js View File

19
   }
19
   }
20
 
20
 
21
   didDisappear() {
21
   didDisappear() {
22
-    alert('didDisappear'); // eslint-disable-line no-alert
22
+    setTimeout(() => {
23
+      alert('didDisappear'); // eslint-disable-line no-alert
24
+    }, 1000);
23
   }
25
   }
24
 
26
 
25
   componentWillUnmount() {
27
   componentWillUnmount() {
35
       <View style={styles.root}>
37
       <View style={styles.root}>
36
         <Text style={styles.h1}>{`Lifecycle Screen`}</Text>
38
         <Text style={styles.h1}>{`Lifecycle Screen`}</Text>
37
         <Text style={styles.h1}>{this.state.text}</Text>
39
         <Text style={styles.h1}>{this.state.text}</Text>
38
-        <Button title="Push to test didDisappear" onPress={this.onClickPush} />
40
+        <Button title="Push to test didDisappear" onPress={this.onClickPush}/>
39
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
41
         <Text style={styles.footer}>{`this.props.containerId = ${this.props.containerId}`}</Text>
40
       </View>
42
       </View>
41
     );
43
     );
42
   }
44
   }
43
 
45
 
44
   onClickPush() {
46
   onClickPush() {
45
-    Navigation.push(this.props.containerId, {
46
-      name: 'navigation.playground.TextScreen'
47
-    });
47
+    Navigation.push(this.props.containerId, { name: 'navigation.playground.TextScreen' });
48
   }
48
   }
49
 }
49
 }
50
 module.exports = LifecycleScreen;
50
 module.exports = LifecycleScreen;

+ 4
- 2
playground/src/containers/OptionsScreen.js View File

100
 
100
 
101
   onClickShowTopBar() {
101
   onClickShowTopBar() {
102
     Navigation.setOptions(this.props.containerId, {
102
     Navigation.setOptions(this.props.containerId, {
103
-      topBarHidden: false
103
+      topBarHidden: false,
104
+      animateTopBarHide: true
104
     });
105
     });
105
   }
106
   }
106
 
107
 
107
   onClickHideTopBar() {
108
   onClickHideTopBar() {
108
     Navigation.setOptions(this.props.containerId, {
109
     Navigation.setOptions(this.props.containerId, {
109
-      topBarHidden: true
110
+      topBarHidden: true,
111
+      animateTopBarHide: true
110
     });
112
     });
111
   }
113
   }
112
 }
114
 }