Browse Source

Bottom tabs attach mode support on iOS (#5733)

Add iOS support for `bottomTabs.attachMode`.
This property controls when BottomTabs children are attached to hierarchy and when their React views are created.

By default, RNN attaches all children at the same time which might impact loading time as a few screens are instantiated at once.
Using `afterInitialTab` or `onSwitchToTab` generally leads to improved start up time.
Yogev Ben David 4 years ago
parent
commit
60c4dfcd72
43 changed files with 621 additions and 198 deletions
  1. 5
    0
      lib/ios/BottomTabsAfterInitialTabAttacher.h
  2. 17
    0
      lib/ios/BottomTabsAfterInitialTabAttacher.m
  3. 15
    0
      lib/ios/BottomTabsAttachMode.h
  4. 21
    0
      lib/ios/BottomTabsAttachMode.m
  5. 13
    0
      lib/ios/BottomTabsAttachModeFactory.h
  6. 29
    0
      lib/ios/BottomTabsAttachModeFactory.m
  7. 8
    0
      lib/ios/BottomTabsBaseAttacher.h
  8. 9
    0
      lib/ios/BottomTabsBaseAttacher.m
  9. 5
    0
      lib/ios/BottomTabsOnSwitchToTabAttacher.h
  10. 13
    0
      lib/ios/BottomTabsOnSwitchToTabAttacher.m
  11. 5
    0
      lib/ios/BottomTabsTogetherAttacher.h
  12. 13
    0
      lib/ios/BottomTabsTogetherAttacher.m
  13. 10
    0
      lib/ios/RNNBottomTabsController.h
  14. 19
    0
      lib/ios/RNNBottomTabsController.m
  15. 2
    0
      lib/ios/RNNBottomTabsOptions.h
  16. 1
    1
      lib/ios/RNNBottomTabsOptions.m
  17. 1
    1
      lib/ios/RNNBridgeManager.m
  18. 67
    54
      lib/ios/RNNCommandsHandler.m
  19. 1
    11
      lib/ios/RNNComponentViewController.h
  20. 22
    43
      lib/ios/RNNComponentViewController.m
  21. 1
    1
      lib/ios/RNNComponentViewCreator.h
  22. 6
    4
      lib/ios/RNNControllerFactory.h
  23. 32
    19
      lib/ios/RNNControllerFactory.m
  24. 7
    0
      lib/ios/RNNExternalViewController.h
  25. 25
    0
      lib/ios/RNNExternalViewController.m
  26. 3
    1
      lib/ios/RNNLayoutProtocol.h
  27. 3
    4
      lib/ios/RNNReactRootViewCreator.m
  28. 1
    1
      lib/ios/RNNReactView.h
  29. 1
    2
      lib/ios/RNNReactView.m
  30. 2
    2
      lib/ios/RNNSideMenuChildVC.m
  31. 86
    6
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  32. 9
    1
      lib/ios/UIViewController+LayoutProtocol.h
  33. 44
    23
      lib/ios/UIViewController+LayoutProtocol.m
  34. 5
    1
      lib/ios/Utils/UITabBarController+RNNUtils.h
  35. 8
    1
      lib/ios/Utils/UITabBarController+RNNUtils.m
  36. 74
    13
      playground/ios/NavigationTests/RNNCommandsHandlerTest.m
  37. 4
    2
      playground/ios/NavigationTests/RNNControllerFactoryTest.m
  38. 10
    3
      playground/ios/NavigationTests/RNNSideMenuControllerTest.m
  39. 1
    1
      playground/ios/NavigationTests/RNNTestRootViewCreator.h
  40. 2
    2
      playground/ios/Podfile.lock
  41. 6
    0
      playground/ios/playground.xcodeproj/project.pbxproj
  42. 14
    0
      playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme
  43. 1
    1
      playground/src/commons/Options.js

+ 5
- 0
lib/ios/BottomTabsAfterInitialTabAttacher.h View File

1
+#import "BottomTabsBaseAttacher.h"
2
+
3
+@interface BottomTabsAfterInitialTabAttacher : BottomTabsBaseAttacher
4
+
5
+@end

+ 17
- 0
lib/ios/BottomTabsAfterInitialTabAttacher.m View File

1
+#import "BottomTabsAfterInitialTabAttacher.h"
2
+#import "UITabBarController+RNNUtils.h"
3
+
4
+@implementation BottomTabsAfterInitialTabAttacher
5
+
6
+- (void)attach:(UITabBarController *)bottomTabsController {
7
+    [bottomTabsController.selectedViewController setReactViewReadyCallback:^{
8
+        [bottomTabsController readyForPresentation];
9
+        for (UIViewController* viewController in bottomTabsController.deselectedViewControllers) {
10
+            [viewController render];
11
+        }
12
+    }];
13
+    
14
+    [bottomTabsController.selectedViewController render];
15
+}
16
+
17
+@end

+ 15
- 0
lib/ios/BottomTabsAttachMode.h View File

1
+#import "Text.h"
2
+
3
+typedef NS_ENUM(NSInteger, AttachMode) {
4
+    BottomTabsAttachModeTogether = 0,
5
+    BottomTabsAttachModeAfterInitialTab,
6
+    BottomTabsAttachModeOnSwitchToTab
7
+};
8
+
9
+@interface BottomTabsAttachMode : Text
10
+
11
+- (AttachMode)get;
12
+
13
+- (AttachMode)getWithDefaultValue:(id)defaultValue;
14
+
15
+@end

+ 21
- 0
lib/ios/BottomTabsAttachMode.m View File

1
+#import "BottomTabsAttachMode.h"
2
+#import <React/RCTConvert.h>
3
+
4
+@implementation BottomTabsAttachMode
5
+
6
+- (AttachMode)get {
7
+    return [self.class AttachMode:[super get]];
8
+}
9
+
10
+- (AttachMode)getWithDefaultValue:(id)defaultValue {
11
+    return [self.class AttachMode:[super getWithDefaultValue:defaultValue]];
12
+}
13
+
14
+RCT_ENUM_CONVERTER(AttachMode,
15
+(@{@"together": @(BottomTabsAttachModeTogether),
16
+   @"afterInitialTab": @(BottomTabsAttachModeAfterInitialTab),
17
+   @"onSwitchToTab": @(BottomTabsAttachModeOnSwitchToTab)
18
+}), BottomTabsAttachModeTogether, integerValue)
19
+
20
+
21
+@end

+ 13
- 0
lib/ios/BottomTabsAttachModeFactory.h View File

1
+#import <Foundation/Foundation.h>
2
+#import "RNNNavigationOptions.h"
3
+#import "BottomTabsBaseAttacher.h"
4
+
5
+@interface BottomTabsAttachModeFactory : NSObject
6
+
7
+- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions;
8
+
9
+- (BottomTabsBaseAttacher *)fromOptions:(RNNNavigationOptions *)options;
10
+
11
+@property (nonatomic, retain) RNNNavigationOptions* defaultOptions;
12
+
13
+@end

+ 29
- 0
lib/ios/BottomTabsAttachModeFactory.m View File

1
+#import "BottomTabsAttachModeFactory.h"
2
+#import "BottomTabsTogetherAttacher.h"
3
+#import "BottomTabsOnSwitchToTabAttacher.h"
4
+#import "BottomTabsAfterInitialTabAttacher.h"
5
+
6
+@implementation BottomTabsAttachModeFactory
7
+
8
+- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions {
9
+	self = [super init];
10
+	_defaultOptions = defaultOptions;
11
+	return self;
12
+}
13
+
14
+- (BottomTabsBaseAttacher *)fromOptions:(RNNNavigationOptions *)options {
15
+    AttachMode attachMode = [[options withDefault:_defaultOptions].bottomTabs.tabsAttachMode getWithDefaultValue:@"together"];
16
+	switch (attachMode) {
17
+        case BottomTabsAttachModeAfterInitialTab: {
18
+            return [BottomTabsAfterInitialTabAttacher new];
19
+        }
20
+        case BottomTabsAttachModeOnSwitchToTab: {
21
+            return [BottomTabsOnSwitchToTabAttacher new];
22
+        }
23
+        default:
24
+            return [BottomTabsTogetherAttacher new];
25
+            break;
26
+    }
27
+}
28
+
29
+@end

+ 8
- 0
lib/ios/BottomTabsBaseAttacher.h View File

1
+#import <Foundation/Foundation.h>
2
+#import "UIViewController+LayoutProtocol.h"
3
+
4
+@interface BottomTabsBaseAttacher : NSObject
5
+
6
+- (void)attach:(UITabBarController *)bottomTabsController;
7
+
8
+@end

+ 9
- 0
lib/ios/BottomTabsBaseAttacher.m View File

1
+#import "BottomTabsBaseAttacher.h"
2
+
3
+@implementation BottomTabsBaseAttacher
4
+
5
+- (void)attach:(UITabBarController *)bottomTabsController {
6
+    
7
+}
8
+
9
+@end

+ 5
- 0
lib/ios/BottomTabsOnSwitchToTabAttacher.h View File

1
+#import "BottomTabsBaseAttacher.h"
2
+
3
+@interface BottomTabsOnSwitchToTabAttacher : BottomTabsBaseAttacher
4
+
5
+@end

+ 13
- 0
lib/ios/BottomTabsOnSwitchToTabAttacher.m View File

1
+#import "BottomTabsOnSwitchToTabAttacher.h"
2
+
3
+@implementation BottomTabsOnSwitchToTabAttacher
4
+
5
+- (void)attach:(UITabBarController *)bottomTabsController {
6
+    [bottomTabsController.selectedViewController setReactViewReadyCallback:^{
7
+        [bottomTabsController readyForPresentation];
8
+    }];
9
+    
10
+    [bottomTabsController.selectedViewController render];
11
+}
12
+
13
+@end

+ 5
- 0
lib/ios/BottomTabsTogetherAttacher.h View File

1
+#import "BottomTabsBaseAttacher.h"
2
+
3
+@interface BottomTabsTogetherAttacher : BottomTabsBaseAttacher
4
+
5
+@end

+ 13
- 0
lib/ios/BottomTabsTogetherAttacher.m View File

1
+#import "BottomTabsTogetherAttacher.h"
2
+
3
+@implementation BottomTabsTogetherAttacher
4
+
5
+- (void)attach:(UITabBarController *)bottomTabsController {
6
+    for (UIViewController* childViewController in bottomTabsController.childViewControllers) {
7
+        [childViewController render];
8
+    }
9
+    
10
+    [bottomTabsController readyForPresentation];
11
+}
12
+
13
+@end

+ 10
- 0
lib/ios/RNNBottomTabsController.h View File

2
 #import "RNNEventEmitter.h"
2
 #import "RNNEventEmitter.h"
3
 #import "RNNBottomTabsPresenter.h"
3
 #import "RNNBottomTabsPresenter.h"
4
 #import "UIViewController+LayoutProtocol.h"
4
 #import "UIViewController+LayoutProtocol.h"
5
+#import "BottomTabsBaseAttacher.h"
5
 
6
 
6
 @interface RNNBottomTabsController : UITabBarController <RNNLayoutProtocol, UITabBarControllerDelegate>
7
 @interface RNNBottomTabsController : UITabBarController <RNNLayoutProtocol, UITabBarControllerDelegate>
7
 
8
 
9
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
10
+                           creator:(id<RNNComponentViewCreator>)creator
11
+                           options:(RNNNavigationOptions *)options
12
+                    defaultOptions:(RNNNavigationOptions *)defaultOptions
13
+                         presenter:(RNNBasePresenter *)presenter
14
+                      eventEmitter:(RNNEventEmitter *)eventEmitter
15
+              childViewControllers:(NSArray *)childViewControllers
16
+                bottomTabsAttacher:(BottomTabsBaseAttacher *)bottomTabsAttacher;
17
+
8
 - (void)setSelectedIndexByComponentID:(NSString *)componentID;
18
 - (void)setSelectedIndexByComponentID:(NSString *)componentID;
9
 
19
 
10
 @end
20
 @end

+ 19
- 0
lib/ios/RNNBottomTabsController.m View File

1
 #import "RNNBottomTabsController.h"
1
 #import "RNNBottomTabsController.h"
2
+#import "UITabBarController+RNNUtils.h"
2
 
3
 
3
 @implementation RNNBottomTabsController {
4
 @implementation RNNBottomTabsController {
4
 	NSUInteger _currentTabIndex;
5
 	NSUInteger _currentTabIndex;
6
+    BottomTabsBaseAttacher* _bottomTabsAttacher;
7
+}
8
+
9
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
10
+                           creator:(id<RNNComponentViewCreator>)creator
11
+                           options:(RNNNavigationOptions *)options
12
+                    defaultOptions:(RNNNavigationOptions *)defaultOptions
13
+                         presenter:(RNNBasePresenter *)presenter
14
+                      eventEmitter:(RNNEventEmitter *)eventEmitter
15
+              childViewControllers:(NSArray *)childViewControllers
16
+                bottomTabsAttacher:(BottomTabsBaseAttacher *)bottomTabsAttacher {
17
+    self = [super initWithLayoutInfo:layoutInfo creator:creator options:options defaultOptions:defaultOptions presenter:presenter eventEmitter:eventEmitter childViewControllers:childViewControllers];
18
+    _bottomTabsAttacher = bottomTabsAttacher;
19
+    return self;
5
 }
20
 }
6
 
21
 
7
 - (id<UITabBarControllerDelegate>)delegate {
22
 - (id<UITabBarControllerDelegate>)delegate {
8
 	return self;
23
 	return self;
9
 }
24
 }
10
 
25
 
26
+- (void)render {
27
+    [_bottomTabsAttacher attach:self];
28
+}
29
+
11
 - (void)viewDidLayoutSubviews {
30
 - (void)viewDidLayoutSubviews {
12
 	[self.presenter viewDidLayoutSubviews];
31
 	[self.presenter viewDidLayoutSubviews];
13
 }
32
 }

+ 2
- 0
lib/ios/RNNBottomTabsOptions.h View File

1
 #import "RNNOptions.h"
1
 #import "RNNOptions.h"
2
+#import "BottomTabsAttachMode.h"
2
 
3
 
3
 @interface RNNBottomTabsOptions : RNNOptions
4
 @interface RNNBottomTabsOptions : RNNOptions
4
 
5
 
18
 @property (nonatomic, strong) Text* barStyle;
19
 @property (nonatomic, strong) Text* barStyle;
19
 @property (nonatomic, strong) Text* fontFamily;
20
 @property (nonatomic, strong) Text* fontFamily;
20
 @property (nonatomic, strong) Text* titleDisplayMode;
21
 @property (nonatomic, strong) Text* titleDisplayMode;
22
+@property (nonatomic, strong) BottomTabsAttachMode* tabsAttachMode;
21
 
23
 
22
 @end
24
 @end

+ 1
- 1
lib/ios/RNNBottomTabsOptions.m View File

15
 	self.hideShadow = [BoolParser parse:dict key:@"hideShadow"];
15
 	self.hideShadow = [BoolParser parse:dict key:@"hideShadow"];
16
 	self.backgroundColor = [ColorParser parse:dict key:@"backgroundColor"];
16
 	self.backgroundColor = [ColorParser parse:dict key:@"backgroundColor"];
17
 	self.fontSize = [NumberParser parse:dict key:@"fontSize"];
17
 	self.fontSize = [NumberParser parse:dict key:@"fontSize"];
18
-	
19
 	self.testID = [TextParser parse:dict key:@"testID"];
18
 	self.testID = [TextParser parse:dict key:@"testID"];
20
 	self.currentTabId = [TextParser parse:dict key:@"currentTabId"];
19
 	self.currentTabId = [TextParser parse:dict key:@"currentTabId"];
21
 	self.barStyle = [TextParser parse:dict key:@"barStyle"];
20
 	self.barStyle = [TextParser parse:dict key:@"barStyle"];
22
 	self.fontFamily = [TextParser parse:dict key:@"fontFamily"];
21
 	self.fontFamily = [TextParser parse:dict key:@"fontFamily"];
23
 	self.titleDisplayMode = [TextParser parse:dict key:@"titleDisplayMode"];
22
 	self.titleDisplayMode = [TextParser parse:dict key:@"titleDisplayMode"];
23
+    self.tabsAttachMode = [TextParser parse:dict key:@"tabsAttachMode"];
24
 	
24
 	
25
 	return self;
25
 	return self;
26
 }
26
 }

+ 1
- 1
lib/ios/RNNBridgeManager.m View File

89
 
89
 
90
 	id<RNNComponentViewCreator> rootViewCreator = [[RNNReactRootViewCreator alloc] initWithBridge:bridge];
90
 	id<RNNComponentViewCreator> rootViewCreator = [[RNNReactRootViewCreator alloc] initWithBridge:bridge];
91
 	_componentRegistry = [[RNNReactComponentRegistry alloc] initWithCreator:rootViewCreator];
91
 	_componentRegistry = [[RNNReactComponentRegistry alloc] initWithCreator:rootViewCreator];
92
-	RNNControllerFactory *controllerFactory = [[RNNControllerFactory alloc] initWithRootViewCreator:rootViewCreator eventEmitter:eventEmitter store:_store componentRegistry:_componentRegistry andBridge:bridge];
92
+	RNNControllerFactory *controllerFactory = [[RNNControllerFactory alloc] initWithRootViewCreator:rootViewCreator eventEmitter:eventEmitter store:_store componentRegistry:_componentRegistry andBridge:bridge bottomTabsAttachModeFactory:[BottomTabsAttachModeFactory new]];
93
 
93
 
94
 	_commandsHandler = [[RNNCommandsHandler alloc] initWithControllerFactory:controllerFactory eventEmitter:eventEmitter stackManager:[RNNNavigationStackManager new] modalManager:_modalManager overlayManager:_overlayManager mainWindow:_mainWindow];
94
 	_commandsHandler = [[RNNCommandsHandler alloc] initWithControllerFactory:controllerFactory eventEmitter:eventEmitter stackManager:[RNNNavigationStackManager new] modalManager:_modalManager overlayManager:_overlayManager mainWindow:_mainWindow];
95
 	RNNBridgeModule *bridgeModule = [[RNNBridgeModule alloc] initWithCommandsHandler:_commandsHandler];
95
 	RNNBridgeModule *bridgeModule = [[RNNBridgeModule alloc] initWithCommandsHandler:_commandsHandler];

+ 67
- 54
lib/ios/RNNCommandsHandler.m View File

72
 	[_modalManager dismissAllModalsAnimated:NO completion:nil];
72
 	[_modalManager dismissAllModalsAnimated:NO completion:nil];
73
 	
73
 	
74
 	UIViewController *vc = [_controllerFactory createLayout:layout[@"root"]];
74
 	UIViewController *vc = [_controllerFactory createLayout:layout[@"root"]];
75
-	
76
-	[vc renderTreeAndWait:[vc.resolveOptions.animations.setRoot.waitForRender getWithDefaultValue:NO] perform:^{
77
-		_mainWindow.rootViewController = vc;
78
-		[_eventEmitter sendOnNavigationCommandCompletion:setRoot commandId:commandId params:@{@"layout": layout}];
79
-		completion() ;
80
-	}];
75
+    vc.waitForRender = [vc.resolveOptionsWithDefault.animations.setRoot.waitForRender getWithDefaultValue:NO];
76
+    
77
+    [vc setReactViewReadyCallback:^{
78
+        _mainWindow.rootViewController = vc;
79
+        [_eventEmitter sendOnNavigationCommandCompletion:setRoot commandId:commandId params:@{@"layout": layout}];
80
+        completion();
81
+    }];
82
+    
83
+	[vc render];
81
 }
84
 }
82
 
85
 
83
 - (void)mergeOptions:(NSString*)componentId options:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
86
 - (void)mergeOptions:(NSString*)componentId options:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
112
 	UIViewController *newVc = [_controllerFactory createLayout:layout];
115
 	UIViewController *newVc = [_controllerFactory createLayout:layout];
113
 	UIViewController *fromVC = [RNNLayoutManager findComponentForId:componentId];
116
 	UIViewController *fromVC = [RNNLayoutManager findComponentForId:componentId];
114
 	
117
 	
115
-	if ([[newVc.resolveOptions.preview.reactTag getWithDefaultValue:@(0)] floatValue] > 0) {
118
+	if ([[newVc.resolveOptionsWithDefault.preview.reactTag getWithDefaultValue:@(0)] floatValue] > 0) {
116
 		UIViewController* vc = [RNNLayoutManager findComponentForId:componentId];
119
 		UIViewController* vc = [RNNLayoutManager findComponentForId:componentId];
117
 		
120
 		
118
 		if([vc isKindOfClass:[RNNComponentViewController class]]) {
121
 		if([vc isKindOfClass:[RNNComponentViewController class]]) {
119
 			RNNComponentViewController* rootVc = (RNNComponentViewController*)vc;
122
 			RNNComponentViewController* rootVc = (RNNComponentViewController*)vc;
120
 			rootVc.previewController = newVc;
123
 			rootVc.previewController = newVc;
121
-			[newVc renderTreeAndWait:NO perform:nil];
124
+			[newVc render];
122
 			
125
 			
123
 			rootVc.previewCallback = ^(UIViewController *vcc) {
126
 			rootVc.previewCallback = ^(UIViewController *vcc) {
124
 				RNNComponentViewController* rvc  = (RNNComponentViewController*)vcc;
127
 				RNNComponentViewController* rvc  = (RNNComponentViewController*)vcc;
125
 				[self->_eventEmitter sendOnPreviewCompleted:componentId previewComponentId:newVc.layoutInfo.componentId];
128
 				[self->_eventEmitter sendOnPreviewCompleted:componentId previewComponentId:newVc.layoutInfo.componentId];
126
-				if ([newVc.resolveOptions.preview.commit getWithDefaultValue:NO]) {
129
+				if ([newVc.resolveOptionsWithDefault.preview.commit getWithDefaultValue:NO]) {
127
 					[CATransaction begin];
130
 					[CATransaction begin];
128
 					[CATransaction setCompletionBlock:^{
131
 					[CATransaction setCompletionBlock:^{
129
 						[self->_eventEmitter sendOnNavigationCommandCompletion:push commandId:commandId params:@{@"componentId": componentId}];
132
 						[self->_eventEmitter sendOnNavigationCommandCompletion:push commandId:commandId params:@{@"componentId": componentId}];
136
 			
139
 			
137
 			CGSize size = CGSizeMake(rootVc.view.frame.size.width, rootVc.view.frame.size.height);
140
 			CGSize size = CGSizeMake(rootVc.view.frame.size.width, rootVc.view.frame.size.height);
138
 			
141
 			
139
-			if (newVc.resolveOptions.preview.width.hasValue) {
140
-				size.width = [newVc.resolveOptions.preview.width.get floatValue];
142
+			if (newVc.resolveOptionsWithDefault.preview.width.hasValue) {
143
+				size.width = [newVc.resolveOptionsWithDefault.preview.width.get floatValue];
141
 			}
144
 			}
142
 			
145
 			
143
-			if (newVc.resolveOptions.preview.height.hasValue) {
144
-				size.height = [newVc.resolveOptions.preview.height.get floatValue];
146
+			if (newVc.resolveOptionsWithDefault.preview.height.hasValue) {
147
+				size.height = [newVc.resolveOptionsWithDefault.preview.height.get floatValue];
145
 			}
148
 			}
146
 			
149
 			
147
-			if (newVc.resolveOptions.preview.width.hasValue || newVc.resolveOptions.preview.height.hasValue) {
150
+			if (newVc.resolveOptionsWithDefault.preview.width.hasValue || newVc.resolveOptionsWithDefault.preview.height.hasValue) {
148
 				newVc.preferredContentSize = size;
151
 				newVc.preferredContentSize = size;
149
 			}
152
 			}
150
 			
153
 			
151
 			RCTExecuteOnMainQueue(^{
154
 			RCTExecuteOnMainQueue(^{
152
-				UIView *view = [[ReactNativeNavigation getBridge].uiManager viewForReactTag:newVc.resolveOptions.preview.reactTag.get];
155
+				UIView *view = [[ReactNativeNavigation getBridge].uiManager viewForReactTag:newVc.resolveOptionsWithDefault.preview.reactTag.get];
153
 				[rootVc registerForPreviewingWithDelegate:(id)rootVc sourceView:view];
156
 				[rootVc registerForPreviewingWithDelegate:(id)rootVc sourceView:view];
154
 			});
157
 			});
155
 		}
158
 		}
156
 	} else {
159
 	} else {
157
-		id animationDelegate = (newVc.resolveOptions.animations.push.hasCustomAnimation || newVc.resolveOptions.customTransition.animations) ? newVc : nil;
158
-		[newVc renderTreeAndWait:([newVc.resolveOptions.animations.push.waitForRender getWithDefaultValue:NO] || animationDelegate) perform:^{
159
-			[_stackManager push:newVc onTop:fromVC animated:[newVc.resolveOptions.animations.push.enable getWithDefaultValue:YES] animationDelegate:animationDelegate completion:^{
160
-				[_eventEmitter sendOnNavigationCommandCompletion:push commandId:commandId params:@{@"componentId": componentId}];
161
-				completion();
162
-			} rejection:rejection];
163
-		}];
160
+		id animationDelegate = (newVc.resolveOptionsWithDefault.animations.push.hasCustomAnimation || newVc.resolveOptionsWithDefault.customTransition.animations) ? newVc : nil;
161
+        newVc.waitForRender = ([newVc.resolveOptionsWithDefault.animations.push.waitForRender getWithDefaultValue:NO] || animationDelegate);
162
+        [newVc setReactViewReadyCallback:^{
163
+            [_stackManager push:newVc onTop:fromVC animated:[newVc.resolveOptionsWithDefault.animations.push.enable getWithDefaultValue:YES] animationDelegate:animationDelegate completion:^{
164
+                [_eventEmitter sendOnNavigationCommandCompletion:push commandId:commandId params:@{@"componentId": componentId}];
165
+                completion();
166
+            } rejection:rejection];
167
+        }];
168
+        
169
+        [newVc render];
164
 	}
170
 	}
165
 }
171
 }
166
 
172
 
170
 	NSArray<UIViewController *> *childViewControllers = [_controllerFactory createChildrenLayout:children];
176
 	NSArray<UIViewController *> *childViewControllers = [_controllerFactory createChildrenLayout:children];
171
 	for (UIViewController<RNNLayoutProtocol>* viewController in childViewControllers) {
177
 	for (UIViewController<RNNLayoutProtocol>* viewController in childViewControllers) {
172
 		if (![viewController isEqual:childViewControllers.lastObject]) {
178
 		if (![viewController isEqual:childViewControllers.lastObject]) {
173
-			[viewController renderTreeAndWait:NO perform:nil];
179
+			[viewController render];
174
 		}
180
 		}
175
 	}
181
 	}
176
 	UIViewController *newVC = childViewControllers.lastObject;
182
 	UIViewController *newVC = childViewControllers.lastObject;
177
 	UIViewController *fromVC = [RNNLayoutManager findComponentForId:componentId];
183
 	UIViewController *fromVC = [RNNLayoutManager findComponentForId:componentId];
178
-	RNNNavigationOptions* options = newVC.resolveOptions;
184
+	RNNNavigationOptions* options = newVC.resolveOptionsWithDefault;
179
 	__weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
185
 	__weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
180
 
186
 
181
-	[newVC renderTreeAndWait:([options.animations.setStackRoot.waitForRender getWithDefaultValue:NO]) perform:^{
182
-		[_stackManager setStackChildren:childViewControllers fromViewController:fromVC animated:[options.animations.setStackRoot.enable getWithDefaultValue:YES] completion:^{
183
-			[weakEventEmitter sendOnNavigationCommandCompletion:setStackRoot commandId:commandId params:@{@"componentId": componentId}];
184
-			completion();
185
-		} rejection:rejection];
186
-	}]; 
187
+    newVC.waitForRender = ([options.animations.setStackRoot.waitForRender getWithDefaultValue:NO]);
188
+    [newVC setReactViewReadyCallback:^{
189
+        [self->_stackManager setStackChildren:childViewControllers fromViewController:fromVC animated:[options.animations.setStackRoot.enable getWithDefaultValue:YES] completion:^{
190
+            [weakEventEmitter sendOnNavigationCommandCompletion:setStackRoot commandId:commandId params:@{@"componentId": componentId}];
191
+            completion();
192
+        } rejection:rejection];
193
+    }];
194
+
195
+    [newVC render];
187
 }
196
 }
188
 
197
 
189
 - (void)pop:(NSString*)componentId commandId:(NSString*)commandId mergeOptions:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
198
 - (void)pop:(NSString*)componentId commandId:(NSString*)commandId mergeOptions:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
196
 	UINavigationController *nvc = vc.navigationController;
205
 	UINavigationController *nvc = vc.navigationController;
197
 	
206
 	
198
 	if ([nvc topViewController] == vc) {
207
 	if ([nvc topViewController] == vc) {
199
-		if (vc.resolveOptions.animations.pop) {
208
+		if (vc.resolveOptionsWithDefault.animations.pop) {
200
 			nvc.delegate = vc;
209
 			nvc.delegate = vc;
201
 		} else {
210
 		} else {
202
 			nvc.delegate = nil;
211
 			nvc.delegate = nil;
204
 	} else {
213
 	} else {
205
 		NSMutableArray * vcs = nvc.viewControllers.mutableCopy;
214
 		NSMutableArray * vcs = nvc.viewControllers.mutableCopy;
206
 		[vcs removeObject:vc];
215
 		[vcs removeObject:vc];
207
-		[nvc setViewControllers:vcs animated:[vc.resolveOptions.animations.pop.enable getWithDefaultValue:YES]];
216
+		[nvc setViewControllers:vcs animated:[vc.resolveOptionsWithDefault.animations.pop.enable getWithDefaultValue:YES]];
208
 	}
217
 	}
209
 	
218
 	
210
-	[_stackManager pop:vc animated:[vc.resolveOptions.animations.pop.enable getWithDefaultValue:YES] completion:^{
219
+	[_stackManager pop:vc animated:[vc.resolveOptionsWithDefault.animations.pop.enable getWithDefaultValue:YES] completion:^{
211
 		[_eventEmitter sendOnNavigationCommandCompletion:pop commandId:commandId params:@{@"componentId": componentId}];
220
 		[_eventEmitter sendOnNavigationCommandCompletion:pop commandId:commandId params:@{@"componentId": componentId}];
212
 		completion();
221
 		completion();
213
 	} rejection:rejection];
222
 	} rejection:rejection];
219
 	RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
228
 	RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
220
 	[vc overrideOptions:options];
229
 	[vc overrideOptions:options];
221
 	
230
 	
222
-	[_stackManager popTo:vc animated:[vc.resolveOptions.animations.pop.enable getWithDefaultValue:YES] completion:^(NSArray *poppedViewControllers) {
231
+	[_stackManager popTo:vc animated:[vc.resolveOptionsWithDefault.animations.pop.enable getWithDefaultValue:YES] completion:^(NSArray *poppedViewControllers) {
223
 		[_eventEmitter sendOnNavigationCommandCompletion:popTo commandId:commandId params:@{@"componentId": componentId}];
232
 		[_eventEmitter sendOnNavigationCommandCompletion:popTo commandId:commandId params:@{@"componentId": componentId}];
224
 		completion();
233
 		completion();
225
 	} rejection:rejection];
234
 	} rejection:rejection];
237
 		completion();
246
 		completion();
238
 	}];
247
 	}];
239
 	
248
 	
240
-	[_stackManager popToRoot:vc animated:[vc.resolveOptions.animations.pop.enable getWithDefaultValue:YES] completion:^(NSArray *poppedViewControllers) {
249
+	[_stackManager popToRoot:vc animated:[vc.resolveOptionsWithDefault.animations.pop.enable getWithDefaultValue:YES] completion:^(NSArray *poppedViewControllers) {
241
 		
250
 		
242
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
251
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
243
 		
252
 		
251
 	
260
 	
252
 	UIViewController *newVc = [_controllerFactory createLayout:layout];
261
 	UIViewController *newVc = [_controllerFactory createLayout:layout];
253
 	
262
 	
254
-	[newVc renderTreeAndWait:[newVc.resolveOptions.animations.showModal.waitForRender getWithDefaultValue:NO] perform:^{
255
-		[_modalManager showModal:newVc animated:[newVc.resolveOptions.animations.showModal.enable getWithDefaultValue:YES] hasCustomAnimation:newVc.resolveOptions.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
256
-			[_eventEmitter sendOnNavigationCommandCompletion:showModal commandId:commandId params:@{@"layout": layout}];
257
-			completion(newVc.layoutInfo.componentId);
258
-		}];
259
-	}];
263
+    newVc.waitForRender = [newVc.resolveOptionsWithDefault.animations.showModal.waitForRender getWithDefaultValue:NO];
264
+    [newVc setReactViewReadyCallback:^{
265
+        [_modalManager showModal:newVc animated:[newVc.resolveOptionsWithDefault.animations.showModal.enable getWithDefaultValue:YES] hasCustomAnimation:newVc.resolveOptionsWithDefault.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
266
+            [self->_eventEmitter sendOnNavigationCommandCompletion:showModal commandId:commandId params:@{@"layout": layout}];
267
+            completion(newVc.layoutInfo.componentId);
268
+        }];
269
+    }];
270
+	[newVc render];
260
 }
271
 }
261
 
272
 
262
 - (void)dismissModal:(NSString*)componentId commandId:(NSString*)commandId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
273
 - (void)dismissModal:(NSString*)componentId commandId:(NSString*)commandId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
274
 	
285
 	
275
 	[CATransaction begin];
286
 	[CATransaction begin];
276
 	[CATransaction setCompletionBlock:^{
287
 	[CATransaction setCompletionBlock:^{
277
-		[_eventEmitter sendOnNavigationCommandCompletion:dismissModal commandId:commandId params:@{@"componentId": componentId}];
288
+        [self->_eventEmitter sendOnNavigationCommandCompletion:dismissModal commandId:commandId params:@{@"componentId": componentId}];
278
 	}];
289
 	}];
279
 	
290
 	
280
 	[_modalManager dismissModal:modalToDismiss completion:completion];
291
 	[_modalManager dismissModal:modalToDismiss completion:completion];
300
 	[self assertReady];
311
 	[self assertReady];
301
 	
312
 	
302
 	UIViewController* overlayVC = [_controllerFactory createLayout:layout];
313
 	UIViewController* overlayVC = [_controllerFactory createLayout:layout];
303
-	[overlayVC renderTreeAndWait:NO perform:^{
304
-		UIWindow* overlayWindow = [[RNNOverlayWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
305
-		overlayWindow.rootViewController = overlayVC;
306
-		if ([overlayVC.resolveOptions.overlay.handleKeyboardEvents getWithDefaultValue:NO]) {
307
-			[_overlayManager showOverlayWindowAsKeyWindow:overlayWindow];
308
-		} else {
309
-			[_overlayManager showOverlayWindow:overlayWindow];
310
-		}
311
-		
312
-		[_eventEmitter sendOnNavigationCommandCompletion:showOverlay commandId:commandId params:@{@"layout": layout}];
313
-		completion();
314
-	}];
314
+    [overlayVC setReactViewReadyCallback:^{UIWindow* overlayWindow = [[RNNOverlayWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
315
+        overlayWindow.rootViewController = overlayVC;
316
+        if ([overlayVC.resolveOptionsWithDefault.overlay.handleKeyboardEvents getWithDefaultValue:NO]) {
317
+            [self->_overlayManager showOverlayWindowAsKeyWindow:overlayWindow];
318
+        } else {
319
+            [self->_overlayManager showOverlayWindow:overlayWindow];
320
+        }
321
+        
322
+        [self->_eventEmitter sendOnNavigationCommandCompletion:showOverlay commandId:commandId params:@{@"layout": layout}];
323
+        completion();
324
+        
325
+    }];
326
+    
327
+    [overlayVC render];
315
 }
328
 }
316
 
329
 
317
 - (void)dismissOverlay:(NSString*)componentId commandId:(NSString*)commandId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
330
 - (void)dismissOverlay:(NSString*)componentId commandId:(NSString*)commandId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {

+ 1
- 11
lib/ios/RNNComponentViewController.h View File

10
 
10
 
11
 typedef void (^PreviewCallback)(UIViewController *vc);
11
 typedef void (^PreviewCallback)(UIViewController *vc);
12
 
12
 
13
-@interface RNNComponentViewController : UIViewController	<RNNLayoutProtocol, UIViewControllerPreviewingDelegate, UISearchResultsUpdating, UISearchBarDelegate, UINavigationControllerDelegate, UISplitViewControllerDelegate>
13
+@interface RNNComponentViewController : UIViewController <RNNLayoutProtocol, UIViewControllerPreviewingDelegate, UISearchResultsUpdating, UISearchBarDelegate, UINavigationControllerDelegate, UISplitViewControllerDelegate>
14
 
14
 
15
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
15
 @property (nonatomic, strong) RNNEventEmitter *eventEmitter;
16
 @property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
16
 @property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
29
 						   options:(RNNNavigationOptions *)options
29
 						   options:(RNNNavigationOptions *)options
30
 					defaultOptions:(RNNNavigationOptions *)defaultOptions;
30
 					defaultOptions:(RNNNavigationOptions *)defaultOptions;
31
 
31
 
32
-- (instancetype)initExternalComponentWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
33
-									   eventEmitter:(RNNEventEmitter*)eventEmitter
34
-										  presenter:(RNNComponentPresenter *)presenter
35
-											options:(RNNNavigationOptions *)options
36
-									 defaultOptions:(RNNNavigationOptions *)defaultOptions;
37
-
38
-- (BOOL)isExternalViewController;
39
-
40
 - (void)onButtonPress:(RNNUIBarButtonItem *)barButtonItem;
32
 - (void)onButtonPress:(RNNUIBarButtonItem *)barButtonItem;
41
 
33
 
42
-- (void)bindViewController:(UIViewController *)viewController;
43
-
44
 @end
34
 @end

+ 22
- 43
lib/ios/RNNComponentViewController.m View File

16
 	return self;
16
 	return self;
17
 }
17
 }
18
 
18
 
19
-- (instancetype)initExternalComponentWithLayoutInfo:(RNNLayoutInfo *)layoutInfo eventEmitter:(RNNEventEmitter *)eventEmitter presenter:(RNNComponentPresenter *)presenter options:(RNNNavigationOptions *)options defaultOptions:(RNNNavigationOptions *)defaultOptions {
20
-	self = [self initWithLayoutInfo:layoutInfo rootViewCreator:nil eventEmitter:eventEmitter presenter:presenter options:options defaultOptions:defaultOptions];
21
-	return self;
22
-}
23
-
24
-- (void)bindViewController:(UIViewController *)viewController {
25
-	[self addChildViewController:viewController];
26
-	[self.view addSubview:viewController.view];
27
-	[viewController didMoveToParentViewController:self];
28
-}
29
-
30
 - (void)setDefaultOptions:(RNNNavigationOptions *)defaultOptions {
19
 - (void)setDefaultOptions:(RNNNavigationOptions *)defaultOptions {
31
     _defaultOptions = defaultOptions;
20
     _defaultOptions = defaultOptions;
32
 	[_presenter setDefaultOptions:defaultOptions];
21
 	[_presenter setDefaultOptions:defaultOptions];
36
 	[self.options overrideOptions:options];
25
 	[self.options overrideOptions:options];
37
 }
26
 }
38
 
27
 
39
-- (void)viewWillAppear:(BOOL)animated{
28
+- (void)viewWillAppear:(BOOL)animated {
40
 	[super viewWillAppear:animated];
29
 	[super viewWillAppear:animated];
41
-	
42
 	[_presenter applyOptions:self.resolveOptions];
30
 	[_presenter applyOptions:self.resolveOptions];
43
-	[_presenter renderComponents:self.resolveOptions perform:nil];
44
-	
45
 	[self.parentViewController onChildWillAppear];
31
 	[self.parentViewController onChildWillAppear];
46
 }
32
 }
47
 
33
 
59
 	[self.eventEmitter sendComponentDidDisappear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
45
 	[self.eventEmitter sendComponentDidDisappear:self.layoutInfo.componentId componentName:self.layoutInfo.name];
60
 }
46
 }
61
 
47
 
62
-- (void)renderTreeAndWait:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock {
63
-	if (self.isExternalViewController) {
64
-		if (readyBlock) {
65
-			readyBlock();
66
-		}
67
-		return;
68
-	}
69
-	
70
-	__block RNNReactViewReadyCompletionBlock readyBlockCopy = readyBlock;
71
-	UIView* reactView = [self.creator createRootView:self.layoutInfo.name rootViewId:self.layoutInfo.componentId availableSize:[UIScreen mainScreen].bounds.size reactViewReadyBlock:^{
72
-		[_presenter renderComponents:self.resolveOptions perform:^{
73
-			if (readyBlockCopy) {
74
-				readyBlockCopy();
75
-				readyBlockCopy = nil;
76
-			}
77
-		}];
78
-	}];
79
-	
80
-	self.view = reactView;
81
-	
82
-	if (!wait && readyBlock) {
83
-		readyBlockCopy();
84
-		readyBlockCopy = nil;
85
-	}
48
+- (void)loadView {
49
+	[self renderReactViewIfNeeded];
50
+}
51
+
52
+- (void)render {
53
+    if (!self.waitForRender)
54
+        [self readyForPresentation];
55
+    else
56
+        [self renderReactViewIfNeeded];
57
+}
58
+
59
+- (void)renderReactViewIfNeeded {
60
+    if (!self.isViewLoaded) {
61
+        self.view = [self.creator createRootView:self.layoutInfo.name rootViewId:self.layoutInfo.componentId reactViewReadyBlock:^{
62
+            [self->_presenter renderComponents:self.resolveOptions perform:^{
63
+                [self readyForPresentation];
64
+            }];
65
+        }];
66
+    } else {
67
+        [self readyForPresentation];
68
+    }
86
 }
69
 }
87
 
70
 
88
 - (UIViewController *)getCurrentChild {
71
 - (UIViewController *)getCurrentChild {
103
 	return self.resolveOptions.customTransition.animations != nil;
86
 	return self.resolveOptions.customTransition.animations != nil;
104
 }
87
 }
105
 
88
 
106
-- (BOOL)isExternalViewController {
107
-	return !self.creator;
108
-}
109
-
110
 - (BOOL)prefersStatusBarHidden {
89
 - (BOOL)prefersStatusBarHidden {
111
 	return [_presenter isStatusBarVisibility:self.navigationController resolvedOptions:self.resolveOptions];
90
 	return [_presenter isStatusBarVisibility:self.navigationController resolvedOptions:self.resolveOptions];
112
 }
91
 }

+ 1
- 1
lib/ios/RNNComponentViewCreator.h View File

5
 
5
 
6
 @protocol RNNComponentViewCreator
6
 @protocol RNNComponentViewCreator
7
 
7
 
8
-- (RNNReactView*)createRootView:(NSString*)name rootViewId:(NSString*)rootViewId availableSize:(CGSize)availableSize reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock;
8
+- (RNNReactView*)createRootView:(NSString*)name rootViewId:(NSString*)rootViewId reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock;
9
 
9
 
10
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions;
10
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions;
11
 
11
 

+ 6
- 4
lib/ios/RNNControllerFactory.h View File

6
 #import "RNNEventEmitter.h"
6
 #import "RNNEventEmitter.h"
7
 #import "RNNReactComponentRegistry.h"
7
 #import "RNNReactComponentRegistry.h"
8
 #import "RNNNavigationOptions.h"
8
 #import "RNNNavigationOptions.h"
9
+#import "BottomTabsAttachModeFactory.h"
9
 
10
 
10
 @interface RNNControllerFactory : NSObject
11
 @interface RNNControllerFactory : NSObject
11
 
12
 
12
 -(instancetype)initWithRootViewCreator:(id <RNNComponentViewCreator>)creator
13
 -(instancetype)initWithRootViewCreator:(id <RNNComponentViewCreator>)creator
13
-						  eventEmitter:(RNNEventEmitter*)eventEmitter
14
-								 store:(RNNExternalComponentStore *)store
15
-					  componentRegistry:(RNNReactComponentRegistry *)componentRegistry
16
-							 andBridge:(RCTBridge*)bridge;
14
+                          eventEmitter:(RNNEventEmitter*)eventEmitter
15
+                                 store:(RNNExternalComponentStore *)store
16
+                     componentRegistry:(RNNReactComponentRegistry *)componentRegistry
17
+                             andBridge:(RCTBridge*)bridge
18
+           bottomTabsAttachModeFactory:(BottomTabsAttachModeFactory *)bottomTabsAttachModeFactory;
17
 
19
 
18
 - (UIViewController *)createLayout:(NSDictionary*)layout;
20
 - (UIViewController *)createLayout:(NSDictionary*)layout;
19
 
21
 

+ 32
- 19
lib/ios/RNNControllerFactory.m View File

5
 #import "RNNBottomTabsController.h"
5
 #import "RNNBottomTabsController.h"
6
 #import "RNNTopTabsViewController.h"
6
 #import "RNNTopTabsViewController.h"
7
 #import "RNNComponentViewController.h"
7
 #import "RNNComponentViewController.h"
8
+#import "RNNExternalViewController.h"
9
+#import "BottomTabsBaseAttacher.h"
10
+#import "BottomTabsAttachModeFactory.h"
8
 
11
 
9
 @implementation RNNControllerFactory {
12
 @implementation RNNControllerFactory {
10
 	id<RNNComponentViewCreator> _creator;
13
 	id<RNNComponentViewCreator> _creator;
11
 	RNNExternalComponentStore *_store;
14
 	RNNExternalComponentStore *_store;
12
 	RCTBridge *_bridge;
15
 	RCTBridge *_bridge;
13
 	RNNReactComponentRegistry* _componentRegistry;
16
 	RNNReactComponentRegistry* _componentRegistry;
17
+    BottomTabsAttachModeFactory* _bottomTabsAttachModeFactory;
14
 }
18
 }
15
 
19
 
16
 # pragma mark public
20
 # pragma mark public
17
 
21
 
18
 
22
 
19
 - (instancetype)initWithRootViewCreator:(id <RNNComponentViewCreator>)creator
23
 - (instancetype)initWithRootViewCreator:(id <RNNComponentViewCreator>)creator
20
-						   eventEmitter:(RNNEventEmitter*)eventEmitter
21
-								  store:(RNNExternalComponentStore *)store
22
-					   componentRegistry:(RNNReactComponentRegistry *)componentRegistry
23
-							  andBridge:(RCTBridge *)bridge {
24
+                           eventEmitter:(RNNEventEmitter*)eventEmitter
25
+                                  store:(RNNExternalComponentStore *)store
26
+                      componentRegistry:(RNNReactComponentRegistry *)componentRegistry
27
+                              andBridge:(RCTBridge *)bridge
28
+            bottomTabsAttachModeFactory:(BottomTabsAttachModeFactory *)bottomTabsAttachModeFactory {
24
 	
29
 	
25
 	self = [super init];
30
 	self = [super init];
26
 	
31
 	
29
 	_bridge = bridge;
34
 	_bridge = bridge;
30
 	_store = store;
35
 	_store = store;
31
 	_componentRegistry = componentRegistry;
36
 	_componentRegistry = componentRegistry;
37
+    _bottomTabsAttachModeFactory = bottomTabsAttachModeFactory;
32
 
38
 
33
 	return self;
39
 	return self;
34
 }
40
 }
35
 
41
 
42
+- (void)setDefaultOptions:(RNNNavigationOptions *)defaultOptions {
43
+    _defaultOptions = defaultOptions;
44
+    _bottomTabsAttachModeFactory.defaultOptions = defaultOptions;
45
+}
46
+
36
 - (UIViewController *)createLayout:(NSDictionary*)layout {
47
 - (UIViewController *)createLayout:(NSDictionary*)layout {
37
 	UIViewController* layoutViewController = [self fromTree:layout];
48
 	UIViewController* layoutViewController = [self fromTree:layout];
38
 	return layoutViewController;
49
 	return layoutViewController;
117
 	
128
 	
118
 	UIViewController* externalVC = [_store getExternalComponent:layoutInfo bridge:_bridge];
129
 	UIViewController* externalVC = [_store getExternalComponent:layoutInfo bridge:_bridge];
119
 	
130
 	
120
-	RNNComponentViewController* component = [[RNNComponentViewController alloc] initExternalComponentWithLayoutInfo:layoutInfo eventEmitter:_eventEmitter presenter:presenter options:options defaultOptions:_defaultOptions];
121
-	[component bindViewController:externalVC];
131
+    RNNExternalViewController* component = [[RNNExternalViewController alloc] initWithLayoutInfo:layoutInfo eventEmitter:_eventEmitter presenter:presenter options:options defaultOptions:_defaultOptions viewController:externalVC];
122
 	
132
 	
123
 	return component;
133
 	return component;
124
 }
134
 }
135
 	return stack;
145
 	return stack;
136
 }
146
 }
137
 
147
 
138
--(UIViewController *)createBottomTabs:(RNNLayoutNode*)node {
139
-	RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
140
-	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
141
-	RNNBottomTabsPresenter* presenter = [[RNNBottomTabsPresenter alloc] initWithDefaultOptions:_defaultOptions];
142
-	NSArray *childViewControllers = [self extractChildrenViewControllersFromNode:node];
143
-	return [[RNNBottomTabsController alloc] initWithLayoutInfo:layoutInfo
144
-																					  creator:_creator
145
-																					  options:options
146
-																			   defaultOptions:_defaultOptions
147
-																					presenter:presenter
148
-																				 eventEmitter:_eventEmitter
149
-																		 childViewControllers:childViewControllers
150
-	];
148
+- (UIViewController *)createBottomTabs:(RNNLayoutNode*)node {
149
+    RNNLayoutInfo* layoutInfo = [[RNNLayoutInfo alloc] initWithNode:node];
150
+    RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
151
+    RNNBottomTabsPresenter* presenter = [[RNNBottomTabsPresenter alloc] initWithDefaultOptions:_defaultOptions];
152
+	BottomTabsBaseAttacher* bottomTabsAttacher = [_bottomTabsAttachModeFactory fromOptions:options];
153
+    
154
+    NSArray *childViewControllers = [self extractChildrenViewControllersFromNode:node];
155
+    return [[RNNBottomTabsController alloc] initWithLayoutInfo:layoutInfo
156
+                                                       creator:_creator
157
+                                                       options:options
158
+                                                defaultOptions:_defaultOptions
159
+                                                     presenter:presenter
160
+                                                  eventEmitter:_eventEmitter
161
+                                          childViewControllers:childViewControllers
162
+                                            bottomTabsAttacher:bottomTabsAttacher
163
+            ];
151
 }
164
 }
152
 
165
 
153
 - (UIViewController *)createTopTabs:(RNNLayoutNode*)node {
166
 - (UIViewController *)createTopTabs:(RNNLayoutNode*)node {

+ 7
- 0
lib/ios/RNNExternalViewController.h View File

1
+#import "RNNComponentViewController.h"
2
+
3
+@interface RNNExternalViewController : RNNComponentViewController
4
+
5
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo eventEmitter:(RNNEventEmitter *)eventEmitter presenter:(RNNComponentPresenter *)presenter options:(RNNNavigationOptions *)options defaultOptions:(RNNNavigationOptions *)defaultOptions viewController:(UIViewController *)viewController;
6
+
7
+@end

+ 25
- 0
lib/ios/RNNExternalViewController.m View File

1
+#import "RNNExternalViewController.h"
2
+
3
+@implementation RNNExternalViewController
4
+
5
+- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo eventEmitter:(RNNEventEmitter *)eventEmitter presenter:(RNNComponentPresenter *)presenter options:(RNNNavigationOptions *)options defaultOptions:(RNNNavigationOptions *)defaultOptions viewController:(UIViewController *)viewController {
6
+	self = [super initWithLayoutInfo:layoutInfo rootViewCreator:nil eventEmitter:eventEmitter presenter:presenter options:options defaultOptions:defaultOptions];
7
+    [self bindViewController:viewController];
8
+	return self;
9
+}
10
+
11
+- (void)bindViewController:(UIViewController *)viewController {
12
+    [self addChildViewController:viewController];
13
+    [self.view addSubview:viewController.view];
14
+    [viewController didMoveToParentViewController:self];
15
+}
16
+
17
+- (void)loadView {
18
+	self.view = [UIView new];
19
+}
20
+
21
+- (void)render {
22
+	[self readyForPresentation];
23
+}
24
+
25
+@end

+ 3
- 1
lib/ios/RNNLayoutProtocol.h View File

17
 					  eventEmitter:(RNNEventEmitter *)eventEmitter
17
 					  eventEmitter:(RNNEventEmitter *)eventEmitter
18
 			  childViewControllers:(NSArray *)childViewControllers;
18
 			  childViewControllers:(NSArray *)childViewControllers;
19
 
19
 
20
-- (void)renderTreeAndWait:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock;
20
+- (void)render;
21
 
21
 
22
 - (UIViewController<RNNLayoutProtocol> *)getCurrentChild;
22
 - (UIViewController<RNNLayoutProtocol> *)getCurrentChild;
23
 
23
 
35
 
35
 
36
 - (void)onChildWillAppear;
36
 - (void)onChildWillAppear;
37
 
37
 
38
+- (void)readyForPresentation;
39
+
38
 @end
40
 @end

+ 3
- 4
lib/ios/RNNReactRootViewCreator.m View File

14
 	return self;
14
 	return self;
15
 }
15
 }
16
 
16
 
17
-- (RNNReactView*)createRootView:(NSString*)name rootViewId:(NSString*)rootViewId availableSize:(CGSize)availableSize reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
17
+- (RNNReactView*)createRootView:(NSString*)name rootViewId:(NSString*)rootViewId reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
18
 	if (!rootViewId) {
18
 	if (!rootViewId) {
19
 		@throw [NSException exceptionWithName:@"MissingViewId" reason:@"Missing view id" userInfo:nil];
19
 		@throw [NSException exceptionWithName:@"MissingViewId" reason:@"Missing view id" userInfo:nil];
20
 	}
20
 	}
22
 	RNNReactView *view = [[RNNReactView alloc] initWithBridge:_bridge
22
 	RNNReactView *view = [[RNNReactView alloc] initWithBridge:_bridge
23
 												   moduleName:name
23
 												   moduleName:name
24
 											initialProperties:@{@"componentId": rootViewId}
24
 											initialProperties:@{@"componentId": rootViewId}
25
-												availableSize:availableSize
26
 										  reactViewReadyBlock:reactViewReadyBlock];
25
 										  reactViewReadyBlock:reactViewReadyBlock];
27
 	return view;
26
 	return view;
28
 }
27
 }
29
 
28
 
30
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions {
29
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions {
31
-	return [self createRootView:componentOptions.name.get rootViewId:componentOptions.componentId.get availableSize:CGSizeZero reactViewReadyBlock:nil];
30
+	return [self createRootView:componentOptions.name.get rootViewId:componentOptions.componentId.get reactViewReadyBlock:nil];
32
 }
31
 }
33
 
32
 
34
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
33
 - (UIView*)createRootViewFromComponentOptions:(RNNComponentOptions*)componentOptions reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
35
-	return [self createRootView:componentOptions.name.get rootViewId:componentOptions.componentId.get availableSize:CGSizeZero reactViewReadyBlock:reactViewReadyBlock];
34
+	return [self createRootView:componentOptions.name.get rootViewId:componentOptions.componentId.get reactViewReadyBlock:reactViewReadyBlock];
36
 }
35
 }
37
 
36
 
38
 @end
37
 @end

+ 1
- 1
lib/ios/RNNReactView.h View File

5
 
5
 
6
 @interface RNNReactView : RCTRootView <RCTRootViewDelegate>
6
 @interface RNNReactView : RCTRootView <RCTRootViewDelegate>
7
 
7
 
8
-- (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties availableSize:(CGSize)availableSize reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock;
8
+- (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock;
9
 
9
 
10
 @property (nonatomic, copy) void (^rootViewDidChangeIntrinsicSize)(CGSize intrinsicSize);
10
 @property (nonatomic, copy) void (^rootViewDidChangeIntrinsicSize)(CGSize intrinsicSize);
11
 @property (nonatomic, copy) RNNReactViewReadyCompletionBlock reactViewReadyBlock;
11
 @property (nonatomic, copy) RNNReactViewReadyCompletionBlock reactViewReadyBlock;

+ 1
- 2
lib/ios/RNNReactView.m View File

6
 	BOOL _fillParent;
6
 	BOOL _fillParent;
7
 }
7
 }
8
 
8
 
9
-- (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties availableSize:(CGSize)availableSize reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
9
+- (instancetype)initWithBridge:(RCTBridge *)bridge moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
10
 	self = [super initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
10
 	self = [super initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
11
 	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentDidAppear:) name:RCTContentDidAppearNotification object:nil];
11
 	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentDidAppear:) name:RCTContentDidAppearNotification object:nil];
12
 	 _reactViewReadyBlock = reactViewReadyBlock;
12
 	 _reactViewReadyBlock = reactViewReadyBlock;
13
-	[bridge.uiManager setAvailableSize:availableSize forRootView:self];
14
 	
13
 	
15
 	return self;
14
 	return self;
16
 }
15
 }

+ 2
- 2
lib/ios/RNNSideMenuChildVC.m View File

17
 	return self;
17
 	return self;
18
 }
18
 }
19
 
19
 
20
-- (void)renderTreeAndWait:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock {
21
-	[self.getCurrentChild renderTreeAndWait:wait perform:readyBlock];
20
+- (void)render {
21
+	[self.getCurrentChild render];
22
 }
22
 }
23
 
23
 
24
 - (void)setChild:(UIViewController<RNNLayoutProtocol> *)child {
24
 - (void)setChild:(UIViewController<RNNLayoutProtocol> *)child {

+ 86
- 6
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

76
 		5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */; };
76
 		5016E8F020209690009D4F7C /* RNNCustomTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */; };
77
 		50175CD1207A2AA1004FE91B /* RNNComponentOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */; };
77
 		50175CD1207A2AA1004FE91B /* RNNComponentOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */; };
78
 		50175CD2207A2AA1004FE91B /* RNNComponentOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */; };
78
 		50175CD2207A2AA1004FE91B /* RNNComponentOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */; };
79
+		5017D9E1239D2C6C00B74047 /* BottomTabsAttachModeFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 5017D9DF239D2C6C00B74047 /* BottomTabsAttachModeFactory.h */; };
80
+		5017D9E2239D2C6C00B74047 /* BottomTabsAttachModeFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 5017D9E0239D2C6C00B74047 /* BottomTabsAttachModeFactory.m */; };
81
+		5017D9E6239D2D9E00B74047 /* BottomTabsBaseAttacher.h in Headers */ = {isa = PBXBuildFile; fileRef = 5017D9E4239D2D9E00B74047 /* BottomTabsBaseAttacher.h */; };
82
+		5017D9E7239D2D9E00B74047 /* BottomTabsBaseAttacher.m in Sources */ = {isa = PBXBuildFile; fileRef = 5017D9E5239D2D9E00B74047 /* BottomTabsBaseAttacher.m */; };
83
+		5017D9EA239D2F9D00B74047 /* BottomTabsTogetherAttacher.h in Headers */ = {isa = PBXBuildFile; fileRef = 5017D9E8239D2F9D00B74047 /* BottomTabsTogetherAttacher.h */; };
84
+		5017D9EB239D2F9D00B74047 /* BottomTabsTogetherAttacher.m in Sources */ = {isa = PBXBuildFile; fileRef = 5017D9E9239D2F9D00B74047 /* BottomTabsTogetherAttacher.m */; };
85
+		5017D9EE239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.h in Headers */ = {isa = PBXBuildFile; fileRef = 5017D9EC239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.h */; };
86
+		5017D9EF239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.m in Sources */ = {isa = PBXBuildFile; fileRef = 5017D9ED239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.m */; };
87
+		5017D9F2239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.h in Headers */ = {isa = PBXBuildFile; fileRef = 5017D9F0239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.h */; };
88
+		5017D9F3239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.m in Sources */ = {isa = PBXBuildFile; fileRef = 5017D9F1239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.m */; };
79
 		501CD31F214A5B6900A6E225 /* RNNLayoutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */; };
89
 		501CD31F214A5B6900A6E225 /* RNNLayoutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */; };
80
 		501CD320214A5B6900A6E225 /* RNNLayoutInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */; };
90
 		501CD320214A5B6900A6E225 /* RNNLayoutInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */; };
81
 		501E0217213E7EA3003365C5 /* RNNReactView.h in Headers */ = {isa = PBXBuildFile; fileRef = 501E0215213E7EA3003365C5 /* RNNReactView.h */; };
91
 		501E0217213E7EA3003365C5 /* RNNReactView.h in Headers */ = {isa = PBXBuildFile; fileRef = 501E0215213E7EA3003365C5 /* RNNReactView.h */; };
86
 		502F0E142178CF8200367CC3 /* UIViewController+RNNOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E132178CF8200367CC3 /* UIViewController+RNNOptionsTest.m */; };
96
 		502F0E142178CF8200367CC3 /* UIViewController+RNNOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E132178CF8200367CC3 /* UIViewController+RNNOptionsTest.m */; };
87
 		502F0E162178D09600367CC3 /* RNNBasePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E152178D09600367CC3 /* RNNBasePresenterTest.m */; };
97
 		502F0E162178D09600367CC3 /* RNNBasePresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E152178D09600367CC3 /* RNNBasePresenterTest.m */; };
88
 		502F0E182179C39900367CC3 /* RNNTabBarPresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E172179C39900367CC3 /* RNNTabBarPresenterTest.m */; };
98
 		502F0E182179C39900367CC3 /* RNNTabBarPresenterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 502F0E172179C39900367CC3 /* RNNTabBarPresenterTest.m */; };
99
+		50344D2823A03DB4004B6A7C /* BottomTabsAttachMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 50344D2623A03DB4004B6A7C /* BottomTabsAttachMode.h */; };
100
+		50344D2923A03DB4004B6A7C /* BottomTabsAttachMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 50344D2723A03DB4004B6A7C /* BottomTabsAttachMode.m */; };
89
 		5038A374216CDDB6009280BC /* UIViewController+SideMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5038A372216CDDB6009280BC /* UIViewController+SideMenuController.h */; };
101
 		5038A374216CDDB6009280BC /* UIViewController+SideMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5038A372216CDDB6009280BC /* UIViewController+SideMenuController.h */; };
90
 		5038A375216CDDB6009280BC /* UIViewController+SideMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5038A373216CDDB6009280BC /* UIViewController+SideMenuController.m */; };
102
 		5038A375216CDDB6009280BC /* UIViewController+SideMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5038A373216CDDB6009280BC /* UIViewController+SideMenuController.m */; };
91
 		5038A377216CF252009280BC /* UITabBarController+RNNOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5038A376216CF252009280BC /* UITabBarController+RNNOptionsTest.m */; };
103
 		5038A377216CF252009280BC /* UITabBarController+RNNOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5038A376216CF252009280BC /* UITabBarController+RNNOptionsTest.m */; };
215
 		50AB0B1C2255F8640039DAED /* UIViewController+LayoutProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */; };
227
 		50AB0B1C2255F8640039DAED /* UIViewController+LayoutProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */; };
216
 		50AB0B1D2255F8640039DAED /* UIViewController+LayoutProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */; };
228
 		50AB0B1D2255F8640039DAED /* UIViewController+LayoutProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */; };
217
 		50AB0B1F22562FA10039DAED /* UIViewController+LayoutProtocolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 50AB0B1E22562FA10039DAED /* UIViewController+LayoutProtocolTest.m */; };
229
 		50AB0B1F22562FA10039DAED /* UIViewController+LayoutProtocolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 50AB0B1E22562FA10039DAED /* UIViewController+LayoutProtocolTest.m */; };
230
+		50BAFE4B2399405800798674 /* RNNExternalViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50BAFE492399405800798674 /* RNNExternalViewController.h */; };
231
+		50BAFE4C2399405800798674 /* RNNExternalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50BAFE4A2399405800798674 /* RNNExternalViewController.m */; };
218
 		50BE951220B5A787004F5DF5 /* RNNStatusBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */; };
232
 		50BE951220B5A787004F5DF5 /* RNNStatusBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */; };
219
 		50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */; };
233
 		50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */; };
220
 		50C4A496206BDDBB00DB292E /* RNNSubtitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */; };
234
 		50C4A496206BDDBB00DB292E /* RNNSubtitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */; };
433
 		5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNCustomTitleView.m; sourceTree = "<group>"; };
447
 		5016E8EE2020968F009D4F7C /* RNNCustomTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNCustomTitleView.m; sourceTree = "<group>"; };
434
 		50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNComponentOptions.h; sourceTree = "<group>"; };
448
 		50175CCF207A2AA1004FE91B /* RNNComponentOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNComponentOptions.h; sourceTree = "<group>"; };
435
 		50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNComponentOptions.m; sourceTree = "<group>"; };
449
 		50175CD0207A2AA1004FE91B /* RNNComponentOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNComponentOptions.m; sourceTree = "<group>"; };
450
+		5017D9DF239D2C6C00B74047 /* BottomTabsAttachModeFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsAttachModeFactory.h; sourceTree = "<group>"; };
451
+		5017D9E0239D2C6C00B74047 /* BottomTabsAttachModeFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsAttachModeFactory.m; sourceTree = "<group>"; };
452
+		5017D9E4239D2D9E00B74047 /* BottomTabsBaseAttacher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsBaseAttacher.h; sourceTree = "<group>"; };
453
+		5017D9E5239D2D9E00B74047 /* BottomTabsBaseAttacher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsBaseAttacher.m; sourceTree = "<group>"; };
454
+		5017D9E8239D2F9D00B74047 /* BottomTabsTogetherAttacher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsTogetherAttacher.h; sourceTree = "<group>"; };
455
+		5017D9E9239D2F9D00B74047 /* BottomTabsTogetherAttacher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsTogetherAttacher.m; sourceTree = "<group>"; };
456
+		5017D9EC239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsAfterInitialTabAttacher.h; sourceTree = "<group>"; };
457
+		5017D9ED239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsAfterInitialTabAttacher.m; sourceTree = "<group>"; };
458
+		5017D9F0239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsOnSwitchToTabAttacher.h; sourceTree = "<group>"; };
459
+		5017D9F1239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsOnSwitchToTabAttacher.m; sourceTree = "<group>"; };
436
 		501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLayoutInfo.h; sourceTree = "<group>"; };
460
 		501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNLayoutInfo.h; sourceTree = "<group>"; };
437
 		501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutInfo.m; sourceTree = "<group>"; };
461
 		501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutInfo.m; sourceTree = "<group>"; };
438
 		501E0215213E7EA3003365C5 /* RNNReactView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactView.h; sourceTree = "<group>"; };
462
 		501E0215213E7EA3003365C5 /* RNNReactView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNReactView.h; sourceTree = "<group>"; };
444
 		502F0E132178CF8200367CC3 /* UIViewController+RNNOptionsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+RNNOptionsTest.m"; sourceTree = "<group>"; };
468
 		502F0E132178CF8200367CC3 /* UIViewController+RNNOptionsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+RNNOptionsTest.m"; sourceTree = "<group>"; };
445
 		502F0E152178D09600367CC3 /* RNNBasePresenterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNBasePresenterTest.m; sourceTree = "<group>"; };
469
 		502F0E152178D09600367CC3 /* RNNBasePresenterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNBasePresenterTest.m; sourceTree = "<group>"; };
446
 		502F0E172179C39900367CC3 /* RNNTabBarPresenterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarPresenterTest.m; sourceTree = "<group>"; };
470
 		502F0E172179C39900367CC3 /* RNNTabBarPresenterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarPresenterTest.m; sourceTree = "<group>"; };
471
+		50344D2623A03DB4004B6A7C /* BottomTabsAttachMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BottomTabsAttachMode.h; sourceTree = "<group>"; };
472
+		50344D2723A03DB4004B6A7C /* BottomTabsAttachMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BottomTabsAttachMode.m; sourceTree = "<group>"; };
447
 		5038A372216CDDB6009280BC /* UIViewController+SideMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+SideMenuController.h"; sourceTree = "<group>"; };
473
 		5038A372216CDDB6009280BC /* UIViewController+SideMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+SideMenuController.h"; sourceTree = "<group>"; };
448
 		5038A373216CDDB6009280BC /* UIViewController+SideMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+SideMenuController.m"; sourceTree = "<group>"; };
474
 		5038A373216CDDB6009280BC /* UIViewController+SideMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+SideMenuController.m"; sourceTree = "<group>"; };
449
 		5038A376216CF252009280BC /* UITabBarController+RNNOptionsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UITabBarController+RNNOptionsTest.m"; sourceTree = "<group>"; };
475
 		5038A376216CF252009280BC /* UITabBarController+RNNOptionsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UITabBarController+RNNOptionsTest.m"; sourceTree = "<group>"; };
571
 		50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+LayoutProtocol.h"; sourceTree = "<group>"; };
597
 		50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+LayoutProtocol.h"; sourceTree = "<group>"; };
572
 		50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+LayoutProtocol.m"; sourceTree = "<group>"; };
598
 		50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+LayoutProtocol.m"; sourceTree = "<group>"; };
573
 		50AB0B1E22562FA10039DAED /* UIViewController+LayoutProtocolTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+LayoutProtocolTest.m"; sourceTree = "<group>"; };
599
 		50AB0B1E22562FA10039DAED /* UIViewController+LayoutProtocolTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+LayoutProtocolTest.m"; sourceTree = "<group>"; };
600
+		50BAFE492399405800798674 /* RNNExternalViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNExternalViewController.h; sourceTree = "<group>"; };
601
+		50BAFE4A2399405800798674 /* RNNExternalViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNExternalViewController.m; sourceTree = "<group>"; };
574
 		50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNStatusBarOptions.m; sourceTree = "<group>"; };
602
 		50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNStatusBarOptions.m; sourceTree = "<group>"; };
575
 		50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNStatusBarOptions.h; sourceTree = "<group>"; };
603
 		50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNStatusBarOptions.h; sourceTree = "<group>"; };
576
 		50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSubtitleOptions.h; sourceTree = "<group>"; };
604
 		50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSubtitleOptions.h; sourceTree = "<group>"; };
829
 				505EDD47214FC4A60071C7DE /* RNNLayoutProtocol.h */,
857
 				505EDD47214FC4A60071C7DE /* RNNLayoutProtocol.h */,
830
 				50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */,
858
 				50AB0B1A2255F8640039DAED /* UIViewController+LayoutProtocol.h */,
831
 				50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */,
859
 				50AB0B1B2255F8640039DAED /* UIViewController+LayoutProtocol.m */,
860
+				26916C941E4B9CCC00D13680 /* RNNComponentViewCreator.h */,
832
 			);
861
 			);
833
 			name = Protocols;
862
 			name = Protocols;
834
 			sourceTree = "<group>";
863
 			sourceTree = "<group>";
835
 		};
864
 		};
865
+		5017D9DE239D2C1300B74047 /* Factories */ = {
866
+			isa = PBXGroup;
867
+			children = (
868
+				7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */,
869
+				7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */,
870
+				5017D9DF239D2C6C00B74047 /* BottomTabsAttachModeFactory.h */,
871
+				5017D9E0239D2C6C00B74047 /* BottomTabsAttachModeFactory.m */,
872
+			);
873
+			name = Factories;
874
+			sourceTree = "<group>";
875
+		};
876
+		5017D9E3239D2CC300B74047 /* Attachers */ = {
877
+			isa = PBXGroup;
878
+			children = (
879
+				5017D9E4239D2D9E00B74047 /* BottomTabsBaseAttacher.h */,
880
+				5017D9E5239D2D9E00B74047 /* BottomTabsBaseAttacher.m */,
881
+				5017D9E8239D2F9D00B74047 /* BottomTabsTogetherAttacher.h */,
882
+				5017D9E9239D2F9D00B74047 /* BottomTabsTogetherAttacher.m */,
883
+				5017D9EC239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.h */,
884
+				5017D9ED239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.m */,
885
+				5017D9F0239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.h */,
886
+				5017D9F1239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.m */,
887
+			);
888
+			name = Attachers;
889
+			sourceTree = "<group>";
890
+		};
836
 		5038A3C3216E2D74009280BC /* Params */ = {
891
 		5038A3C3216E2D74009280BC /* Params */ = {
837
 			isa = PBXGroup;
892
 			isa = PBXGroup;
838
 			children = (
893
 			children = (
875
 				503955962174864E00B0A663 /* NullDouble.m */,
930
 				503955962174864E00B0A663 /* NullDouble.m */,
876
 				309877ADF638DF25FF0DA8A1 /* NoColor.m */,
931
 				309877ADF638DF25FF0DA8A1 /* NoColor.m */,
877
 				309874C5B132A51A03DAA3BF /* NoColor.h */,
932
 				309874C5B132A51A03DAA3BF /* NoColor.h */,
933
+				50344D2623A03DB4004B6A7C /* BottomTabsAttachMode.h */,
934
+				50344D2723A03DB4004B6A7C /* BottomTabsAttachMode.m */,
878
 			);
935
 			);
879
 			name = Params;
936
 			name = Params;
880
 			sourceTree = "<group>";
937
 			sourceTree = "<group>";
1003
 			name = HMSegmentControl;
1060
 			name = HMSegmentControl;
1004
 			sourceTree = "<group>";
1061
 			sourceTree = "<group>";
1005
 		};
1062
 		};
1063
+		50BAFE482399403200798674 /* Child View Controllers */ = {
1064
+			isa = PBXGroup;
1065
+			children = (
1066
+				7BEF0D161E437684003E96B0 /* RNNComponentViewController.h */,
1067
+				7BEF0D171E437684003E96B0 /* RNNComponentViewController.m */,
1068
+				50BAFE492399405800798674 /* RNNExternalViewController.h */,
1069
+				50BAFE4A2399405800798674 /* RNNExternalViewController.m */,
1070
+			);
1071
+			name = "Child View Controllers";
1072
+			sourceTree = "<group>";
1073
+		};
1006
 		50D031312005146C00386B3D /* Managers */ = {
1074
 		50D031312005146C00386B3D /* Managers */ = {
1007
 			isa = PBXGroup;
1075
 			isa = PBXGroup;
1008
 			children = (
1076
 			children = (
1031
 				505EDD39214FA7E80071C7DE /* Presenters */,
1099
 				505EDD39214FA7E80071C7DE /* Presenters */,
1032
 				5012242C2173E0A4000F5F98 /* Parent ViewControllers */,
1100
 				5012242C2173E0A4000F5F98 /* Parent ViewControllers */,
1033
 				5012242D2173E0E0000F5F98 /* Protocols */,
1101
 				5012242D2173E0E0000F5F98 /* Protocols */,
1102
+				50BAFE482399403200798674 /* Child View Controllers */,
1034
 				50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */,
1103
 				50570BE82063E09B006A1B5C /* RNNTitleViewHelper.h */,
1104
+				50570BE92063E09B006A1B5C /* RNNTitleViewHelper.m */,
1035
 				501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */,
1105
 				501CD31D214A5B6900A6E225 /* RNNLayoutInfo.h */,
1036
 				501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */,
1106
 				501CD31E214A5B6900A6E225 /* RNNLayoutInfo.m */,
1037
 				501E0215213E7EA3003365C5 /* RNNReactView.h */,
1107
 				501E0215213E7EA3003365C5 /* RNNReactView.h */,
1038
 				501E0216213E7EA3003365C5 /* RNNReactView.m */,
1108
 				501E0216213E7EA3003365C5 /* RNNReactView.m */,
1039
-				50570BE92063E09B006A1B5C /* RNNTitleViewHelper.m */,
1040
-				26916C941E4B9CCC00D13680 /* RNNComponentViewCreator.h */,
1041
 				26916C961E4B9E7700D13680 /* RNNReactRootViewCreator.h */,
1109
 				26916C961E4B9E7700D13680 /* RNNReactRootViewCreator.h */,
1042
 				26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */,
1110
 				26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */,
1043
 				7BA500761E254908001B9E1B /* RNNSplashScreen.h */,
1111
 				7BA500761E254908001B9E1B /* RNNSplashScreen.h */,
1044
 				7BA500771E254908001B9E1B /* RNNSplashScreen.m */,
1112
 				7BA500771E254908001B9E1B /* RNNSplashScreen.m */,
1045
 				7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */,
1113
 				7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */,
1046
 				7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */,
1114
 				7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */,
1047
-				7BEF0D161E437684003E96B0 /* RNNComponentViewController.h */,
1048
-				7BEF0D171E437684003E96B0 /* RNNComponentViewController.m */,
1049
-				7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */,
1050
-				7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */,
1051
 				21B85E5E1F44482A00B314B5 /* RNNNavigationButtons.h */,
1115
 				21B85E5E1F44482A00B314B5 /* RNNNavigationButtons.h */,
1052
 				21B85E5C1F44480200B314B5 /* RNNNavigationButtons.m */,
1116
 				21B85E5C1F44480200B314B5 /* RNNNavigationButtons.m */,
1053
 				214545261F4DC164006E8DA1 /* RNNUIBarButtonItem.h */,
1117
 				214545261F4DC164006E8DA1 /* RNNUIBarButtonItem.h */,
1136
 			children = (
1200
 			children = (
1137
 				E5F6C39B22DB4CB90093C2CE /* Utils */,
1201
 				E5F6C39B22DB4CB90093C2CE /* Utils */,
1138
 				214545271F4DC7ED006E8DA1 /* Helpers */,
1202
 				214545271F4DC7ED006E8DA1 /* Helpers */,
1203
+				5017D9DE239D2C1300B74047 /* Factories */,
1204
+				5017D9E3239D2CC300B74047 /* Attachers */,
1139
 				7BA500731E2544B9001B9E1B /* ReactNativeNavigation.h */,
1205
 				7BA500731E2544B9001B9E1B /* ReactNativeNavigation.h */,
1140
 				7BA500741E2544B9001B9E1B /* ReactNativeNavigation.m */,
1206
 				7BA500741E2544B9001B9E1B /* ReactNativeNavigation.m */,
1141
 				2DCD9193200014A900EDC75D /* RNNBridgeManager.h */,
1207
 				2DCD9193200014A900EDC75D /* RNNBridgeManager.h */,
1314
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
1380
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
1315
 				5038A3D2216E364C009280BC /* Text.h in Headers */,
1381
 				5038A3D2216E364C009280BC /* Text.h in Headers */,
1316
 				261F0E641E6EC94900989DE2 /* RNNModalManager.h in Headers */,
1382
 				261F0E641E6EC94900989DE2 /* RNNModalManager.h in Headers */,
1383
+				50344D2823A03DB4004B6A7C /* BottomTabsAttachMode.h in Headers */,
1317
 				5012242621737278000F5F98 /* NullImage.h in Headers */,
1384
 				5012242621737278000F5F98 /* NullImage.h in Headers */,
1318
 				5038A3B9216DFCFD009280BC /* UITabBarController+RNNOptions.h in Headers */,
1385
 				5038A3B9216DFCFD009280BC /* UITabBarController+RNNOptions.h in Headers */,
1319
 				50644A2020E11A720026709C /* Constants.h in Headers */,
1386
 				50644A2020E11A720026709C /* Constants.h in Headers */,
1323
 				E8367B801F7A8A4700675C05 /* VICMAImageView.h in Headers */,
1390
 				E8367B801F7A8A4700675C05 /* VICMAImageView.h in Headers */,
1324
 				263905E61E4CAC950023D7D3 /* RNNSideMenuChildVC.h in Headers */,
1391
 				263905E61E4CAC950023D7D3 /* RNNSideMenuChildVC.h in Headers */,
1325
 				50F5DFC51F407AA0001A00BC /* RNNStackController.h in Headers */,
1392
 				50F5DFC51F407AA0001A00BC /* RNNStackController.h in Headers */,
1393
+				50BAFE4B2399405800798674 /* RNNExternalViewController.h in Headers */,
1326
 				5047E4F42267568800908DD3 /* RNNExternalComponentStore.h in Headers */,
1394
 				5047E4F42267568800908DD3 /* RNNExternalComponentStore.h in Headers */,
1327
 				21B85E5F1F44482A00B314B5 /* RNNNavigationButtons.h in Headers */,
1395
 				21B85E5F1F44482A00B314B5 /* RNNNavigationButtons.h in Headers */,
1328
 				7BEF0D181E437684003E96B0 /* RNNComponentViewController.h in Headers */,
1396
 				7BEF0D181E437684003E96B0 /* RNNComponentViewController.h in Headers */,
1333
 				50E5F7952240EBD6002AFEAD /* RNNAnimationsTransitionDelegate.h in Headers */,
1401
 				50E5F7952240EBD6002AFEAD /* RNNAnimationsTransitionDelegate.h in Headers */,
1334
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
1402
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
1335
 				E8A430111F9CB87B00B61A20 /* RNNAnimatedView.h in Headers */,
1403
 				E8A430111F9CB87B00B61A20 /* RNNAnimatedView.h in Headers */,
1404
+				5017D9E1239D2C6C00B74047 /* BottomTabsAttachModeFactory.h in Headers */,
1336
 				E5F6C3AC22DB4D0F0093C2CE /* UITabBarController+RNNUtils.h in Headers */,
1405
 				E5F6C3AC22DB4D0F0093C2CE /* UITabBarController+RNNUtils.h in Headers */,
1337
 				506317AA220B547400B26FC3 /* UIImage+insets.h in Headers */,
1406
 				506317AA220B547400B26FC3 /* UIImage+insets.h in Headers */,
1338
 				5038A3C6216E2D93009280BC /* Number.h in Headers */,
1407
 				5038A3C6216E2D93009280BC /* Number.h in Headers */,
1349
 				50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */,
1418
 				50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */,
1350
 				50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */,
1419
 				50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */,
1351
 				50495956216F6B3D006D2B81 /* DictionaryParser.h in Headers */,
1420
 				50495956216F6B3D006D2B81 /* DictionaryParser.h in Headers */,
1421
+				5017D9E6239D2D9E00B74047 /* BottomTabsBaseAttacher.h in Headers */,
1352
 				4534E72520CB6724009F8185 /* RNNLargeTitleOptions.h in Headers */,
1422
 				4534E72520CB6724009F8185 /* RNNLargeTitleOptions.h in Headers */,
1353
 				390AD477200F499D00A8250D /* RNNSwizzles.h in Headers */,
1423
 				390AD477200F499D00A8250D /* RNNSwizzles.h in Headers */,
1354
 				263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
1424
 				263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
1361
 				50495952216F62BD006D2B81 /* NullNumber.h in Headers */,
1431
 				50495952216F62BD006D2B81 /* NullNumber.h in Headers */,
1362
 				5012242221736883000F5F98 /* NullColor.h in Headers */,
1432
 				5012242221736883000F5F98 /* NullColor.h in Headers */,
1363
 				50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */,
1433
 				50570B262061473D006A1B5C /* RNNTitleOptions.h in Headers */,
1434
+				5017D9EE239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.h in Headers */,
1364
 				50395593217485B000B0A663 /* Double.h in Headers */,
1435
 				50395593217485B000B0A663 /* Double.h in Headers */,
1365
 				5050465421F8F4490035497A /* RNNReactComponentRegistry.h in Headers */,
1436
 				5050465421F8F4490035497A /* RNNReactComponentRegistry.h in Headers */,
1366
 				504AFE741FFFF0540076E904 /* RNNTopTabsOptions.h in Headers */,
1437
 				504AFE741FFFF0540076E904 /* RNNTopTabsOptions.h in Headers */,
1389
 				505EDD4A214FDA800071C7DE /* RCTConvert+Modal.h in Headers */,
1460
 				505EDD4A214FDA800071C7DE /* RCTConvert+Modal.h in Headers */,
1390
 				5049595A216F6B46006D2B81 /* NullDictionary.h in Headers */,
1461
 				5049595A216F6B46006D2B81 /* NullDictionary.h in Headers */,
1391
 				501224062173592D000F5F98 /* RNNBottomTabsPresenter.h in Headers */,
1462
 				501224062173592D000F5F98 /* RNNBottomTabsPresenter.h in Headers */,
1463
+				5017D9F2239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.h in Headers */,
1392
 				50706E6D20CE7CA5003345C3 /* UIImage+tint.h in Headers */,
1464
 				50706E6D20CE7CA5003345C3 /* UIImage+tint.h in Headers */,
1393
 				50A246372395399700A192C5 /* RNNModalOptions.h in Headers */,
1465
 				50A246372395399700A192C5 /* RNNModalOptions.h in Headers */,
1394
 				309874B40D202C9718F15CBD /* UIView+Utils.h in Headers */,
1466
 				309874B40D202C9718F15CBD /* UIView+Utils.h in Headers */,
1398
 				3098730BC3B4DE41104D9CC4 /* RNNDotIndicatorPresenter.h in Headers */,
1470
 				3098730BC3B4DE41104D9CC4 /* RNNDotIndicatorPresenter.h in Headers */,
1399
 				309877F473AECC05FB3B9362 /* UITabBarController+RNNUtils.h in Headers */,
1471
 				309877F473AECC05FB3B9362 /* UITabBarController+RNNUtils.h in Headers */,
1400
 				3098702E6833E5CC16D91CE3 /* NoColor.h in Headers */,
1472
 				3098702E6833E5CC16D91CE3 /* NoColor.h in Headers */,
1473
+				5017D9EA239D2F9D00B74047 /* BottomTabsTogetherAttacher.h in Headers */,
1401
 			);
1474
 			);
1402
 			runOnlyForDeploymentPostprocessing = 0;
1475
 			runOnlyForDeploymentPostprocessing = 0;
1403
 		};
1476
 		};
1615
 				507F43CA1FF4F9CC00D9425B /* RNNTopTabOptions.m in Sources */,
1688
 				507F43CA1FF4F9CC00D9425B /* RNNTopTabOptions.m in Sources */,
1616
 				26916C991E4B9E7700D13680 /* RNNReactRootViewCreator.m in Sources */,
1689
 				26916C991E4B9E7700D13680 /* RNNReactRootViewCreator.m in Sources */,
1617
 				5064495E20DC62B90026709C /* RNNSideMenuSideOptions.m in Sources */,
1690
 				5064495E20DC62B90026709C /* RNNSideMenuSideOptions.m in Sources */,
1691
+				5017D9EB239D2F9D00B74047 /* BottomTabsTogetherAttacher.m in Sources */,
1618
 				E5F6C3AD22DB4D0F0093C2CE /* UITabBarController+RNNUtils.m in Sources */,
1692
 				E5F6C3AD22DB4D0F0093C2CE /* UITabBarController+RNNUtils.m in Sources */,
1619
 				214545251F4DC125006E8DA1 /* RNNUIBarButtonItem.m in Sources */,
1693
 				214545251F4DC125006E8DA1 /* RNNUIBarButtonItem.m in Sources */,
1620
 				263905B81E4C6F440023D7D3 /* UIViewController+MMDrawerController.m in Sources */,
1694
 				263905B81E4C6F440023D7D3 /* UIViewController+MMDrawerController.m in Sources */,
1621
 				505EDD3D214FA8000071C7DE /* RNNComponentPresenter.m in Sources */,
1695
 				505EDD3D214FA8000071C7DE /* RNNComponentPresenter.m in Sources */,
1622
 				E33AC20820B5C4F90090DB8A /* RNNSplitViewOptions.m in Sources */,
1696
 				E33AC20820B5C4F90090DB8A /* RNNSplitViewOptions.m in Sources */,
1623
 				E33AC20020B5BA0B0090DB8A /* RNNSplitViewController.m in Sources */,
1697
 				E33AC20020B5BA0B0090DB8A /* RNNSplitViewController.m in Sources */,
1698
+				50BAFE4C2399405800798674 /* RNNExternalViewController.m in Sources */,
1624
 				5038A3C2216E1E66009280BC /* RNNFontAttributesCreator.m in Sources */,
1699
 				5038A3C2216E1E66009280BC /* RNNFontAttributesCreator.m in Sources */,
1625
 				506317AB220B547400B26FC3 /* UIImage+insets.m in Sources */,
1700
 				506317AB220B547400B26FC3 /* UIImage+insets.m in Sources */,
1626
 				E8A430121F9CB87B00B61A20 /* RNNAnimatedView.m in Sources */,
1701
 				E8A430121F9CB87B00B61A20 /* RNNAnimatedView.m in Sources */,
1627
 				507F43F51FF4FCFE00D9425B /* HMSegmentedControl.m in Sources */,
1702
 				507F43F51FF4FCFE00D9425B /* HMSegmentedControl.m in Sources */,
1703
+				5017D9E7239D2D9E00B74047 /* BottomTabsBaseAttacher.m in Sources */,
1628
 				5012242321736883000F5F98 /* NullColor.m in Sources */,
1704
 				5012242321736883000F5F98 /* NullColor.m in Sources */,
1629
 				50451D0A2042E20600695F00 /* RNNAnimationsOptions.m in Sources */,
1705
 				50451D0A2042E20600695F00 /* RNNAnimationsOptions.m in Sources */,
1630
 				5039558C2174829400B0A663 /* IntNumberParser.m in Sources */,
1706
 				5039558C2174829400B0A663 /* IntNumberParser.m in Sources */,
1631
 				507F43C61FF4F17C00D9425B /* RNNTopTabsViewController.m in Sources */,
1707
 				507F43C61FF4F17C00D9425B /* RNNTopTabsViewController.m in Sources */,
1632
 				50706E6E20CE7CA5003345C3 /* UIImage+tint.m in Sources */,
1708
 				50706E6E20CE7CA5003345C3 /* UIImage+tint.m in Sources */,
1709
+				50344D2923A03DB4004B6A7C /* BottomTabsAttachMode.m in Sources */,
1633
 				501224072173592D000F5F98 /* RNNBottomTabsPresenter.m in Sources */,
1710
 				501224072173592D000F5F98 /* RNNBottomTabsPresenter.m in Sources */,
1634
 				50A00C38200F84D6000F01A6 /* RNNOverlayOptions.m in Sources */,
1711
 				50A00C38200F84D6000F01A6 /* RNNOverlayOptions.m in Sources */,
1635
 				5039559C2174867000B0A663 /* DoubleParser.m in Sources */,
1712
 				5039559C2174867000B0A663 /* DoubleParser.m in Sources */,
1713
+				5017D9EF239D2FAF00B74047 /* BottomTabsAfterInitialTabAttacher.m in Sources */,
1636
 				5008641223856A2D00A55BE9 /* UITabBar+utils.m in Sources */,
1714
 				5008641223856A2D00A55BE9 /* UITabBar+utils.m in Sources */,
1637
 				E5F6C3A822DB4D0F0093C2CE /* UIView+Utils.m in Sources */,
1715
 				E5F6C3A822DB4D0F0093C2CE /* UIView+Utils.m in Sources */,
1638
 				5049593F216F5D73006D2B81 /* BoolParser.m in Sources */,
1716
 				5049593F216F5D73006D2B81 /* BoolParser.m in Sources */,
1656
 				E8E5182F1F83A48B000467AC /* RNNTransitionStateHolder.m in Sources */,
1734
 				E8E5182F1F83A48B000467AC /* RNNTransitionStateHolder.m in Sources */,
1657
 				263905B61E4C6F440023D7D3 /* MMExampleDrawerVisualStateManager.m in Sources */,
1735
 				263905B61E4C6F440023D7D3 /* MMExampleDrawerVisualStateManager.m in Sources */,
1658
 				5038A3D3216E364C009280BC /* Text.m in Sources */,
1736
 				5038A3D3216E364C009280BC /* Text.m in Sources */,
1737
+				5017D9E2239D2C6C00B74047 /* BottomTabsAttachModeFactory.m in Sources */,
1659
 				5012240F21735999000F5F98 /* RNNBasePresenter.m in Sources */,
1738
 				5012240F21735999000F5F98 /* RNNBasePresenter.m in Sources */,
1660
 				5038A375216CDDB6009280BC /* UIViewController+SideMenuController.m in Sources */,
1739
 				5038A375216CDDB6009280BC /* UIViewController+SideMenuController.m in Sources */,
1661
 				E8E518331F83B3E0000467AC /* RNNUtils.m in Sources */,
1740
 				E8E518331F83B3E0000467AC /* RNNUtils.m in Sources */,
1669
 				30987AB5137F264FA06DA289 /* DotIndicatorOptions.m in Sources */,
1748
 				30987AB5137F264FA06DA289 /* DotIndicatorOptions.m in Sources */,
1670
 				30987D71FB4FEEAC8D8978E8 /* DotIndicatorParser.m in Sources */,
1749
 				30987D71FB4FEEAC8D8978E8 /* DotIndicatorParser.m in Sources */,
1671
 				30987B23F288EB3A78B7F27C /* RNNDotIndicatorPresenter.m in Sources */,
1750
 				30987B23F288EB3A78B7F27C /* RNNDotIndicatorPresenter.m in Sources */,
1751
+				5017D9F3239D2FCB00B74047 /* BottomTabsOnSwitchToTabAttacher.m in Sources */,
1672
 				309878CC9D33CE1CF991EBD1 /* NoColor.m in Sources */,
1752
 				309878CC9D33CE1CF991EBD1 /* NoColor.m in Sources */,
1673
 			);
1753
 			);
1674
 			runOnlyForDeploymentPostprocessing = 0;
1754
 			runOnlyForDeploymentPostprocessing = 0;

+ 9
- 1
lib/ios/UIViewController+LayoutProtocol.h View File

6
 
6
 
7
 @interface UIViewController (LayoutProtocol) <RNNLayoutProtocol>
7
 @interface UIViewController (LayoutProtocol) <RNNLayoutProtocol>
8
 
8
 
9
-- (void)renderTreeAndWait:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock;
9
+- (void)render;
10
 
10
 
11
 - (UIViewController *)getCurrentChild;
11
 - (UIViewController *)getCurrentChild;
12
 
12
 
13
+- (UIViewController *)presentedComponentViewController;
14
+
13
 - (void)mergeOptions:(RNNNavigationOptions *)options;
15
 - (void)mergeOptions:(RNNNavigationOptions *)options;
14
 
16
 
15
 - (void)mergeChildOptions:(RNNNavigationOptions *)options;
17
 - (void)mergeChildOptions:(RNNNavigationOptions *)options;
16
 
18
 
17
 - (RNNNavigationOptions *)resolveOptions;
19
 - (RNNNavigationOptions *)resolveOptions;
18
 
20
 
21
+- (RNNNavigationOptions *)resolveOptionsWithDefault;
22
+
19
 - (void)setDefaultOptions:(RNNNavigationOptions *)defaultOptions;
23
 - (void)setDefaultOptions:(RNNNavigationOptions *)defaultOptions;
20
 
24
 
21
 - (void)overrideOptions:(RNNNavigationOptions *)options;
25
 - (void)overrideOptions:(RNNNavigationOptions *)options;
22
 
26
 
27
+- (void)readyForPresentation;
28
+
23
 @property (nonatomic, retain) RNNBasePresenter* presenter;
29
 @property (nonatomic, retain) RNNBasePresenter* presenter;
24
 @property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
30
 @property (nonatomic, retain) RNNLayoutInfo* layoutInfo;
25
 @property (nonatomic, strong) RNNNavigationOptions* options;
31
 @property (nonatomic, strong) RNNNavigationOptions* options;
26
 @property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
32
 @property (nonatomic, strong) RNNNavigationOptions* defaultOptions;
27
 @property (nonatomic, strong) RNNEventEmitter* eventEmitter;
33
 @property (nonatomic, strong) RNNEventEmitter* eventEmitter;
28
 @property (nonatomic) id<RNNComponentViewCreator> creator;
34
 @property (nonatomic) id<RNNComponentViewCreator> creator;
35
+@property (nonatomic) RNNReactViewReadyCompletionBlock reactViewReadyCallback;
36
+@property (nonatomic) BOOL waitForRender;
29
 
37
 
30
 @end
38
 @end

+ 44
- 23
lib/ios/UIViewController+LayoutProtocol.m View File

43
     return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
43
     return (RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy];
44
 }
44
 }
45
 
45
 
46
+- (RNNNavigationOptions *)resolveOptionsWithDefault {
47
+    return [(RNNNavigationOptions *) [self.options mergeInOptions:self.getCurrentChild.resolveOptions.copy] withDefault:self.defaultOptions];
48
+}
49
+
46
 - (void)overrideOptions:(RNNNavigationOptions *)options {
50
 - (void)overrideOptions:(RNNNavigationOptions *)options {
47
 	[self.options overrideOptions:options];
51
 	[self.options overrideOptions:options];
48
 }
52
 }
52
 	return interfaceOrientationMask;
56
 	return interfaceOrientationMask;
53
 }
57
 }
54
 
58
 
55
-- (void)renderTreeAndWait:(BOOL)wait perform:(RNNReactViewReadyCompletionBlock)readyBlock {
56
-	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
57
-		dispatch_group_t group = dispatch_group_create();
58
-		for (UIViewController* childViewController in self.childViewControllers) {
59
-			dispatch_group_enter(group);
60
-			dispatch_async(dispatch_get_main_queue(), ^{
61
-				[childViewController renderTreeAndWait:wait perform:^{
62
-					dispatch_group_leave(group);
63
-				}];
64
-			});
65
-		}
66
-		
67
-		dispatch_group_enter(group);
68
-		[self.presenter renderComponents:self.resolveOptions perform:^{
69
-			dispatch_group_leave(group);
70
-		}];
71
-		dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
72
-		
73
-		dispatch_async(dispatch_get_main_queue(), ^{
74
-			readyBlock();
75
-		});
76
-	});
59
+- (void)render {
60
+    if (!self.waitForRender) {
61
+        [self readyForPresentation];
62
+    }
63
+    
64
+    [self.presentedComponentViewController setReactViewReadyCallback:^{
65
+        [self.presenter renderComponents:self.resolveOptionsWithDefault perform:^{
66
+            [self readyForPresentation];
67
+        }];
68
+    }];
69
+    
70
+    [self.presentedComponentViewController render];
71
+}
72
+
73
+- (void)readyForPresentation {
74
+    if (self.reactViewReadyCallback) {
75
+        self.reactViewReadyCallback();
76
+        self.reactViewReadyCallback = nil;
77
+    }
78
+    
79
+    [self.parentViewController readyForPresentation];
77
 }
80
 }
78
 
81
 
79
 - (UIViewController *)getCurrentChild {
82
 - (UIViewController *)getCurrentChild {
80
-	return nil;
83
+    return nil;
84
+}
85
+
86
+- (UIViewController *)presentedComponentViewController {
87
+    return self.getCurrentChild ? self.getCurrentChild.presentedComponentViewController : self;
81
 }
88
 }
82
 
89
 
83
 - (CGFloat)getTopBarHeight {
90
 - (CGFloat)getTopBarHeight {
159
 	objc_setAssociatedObject(self, @selector(creator), creator, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
166
 	objc_setAssociatedObject(self, @selector(creator), creator, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
160
 }
167
 }
161
 
168
 
169
+- (RNNReactViewReadyCompletionBlock)reactViewReadyCallback {
170
+    return objc_getAssociatedObject(self, @selector(reactViewReadyCallback));
171
+}
172
+
173
+- (void)setReactViewReadyCallback:(RNNReactViewReadyCompletionBlock)reactViewReadyCallback {
174
+    objc_setAssociatedObject(self, @selector(reactViewReadyCallback), reactViewReadyCallback, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
175
+}
176
+
177
+- (BOOL)waitForRender {
178
+    return [objc_getAssociatedObject(self.parentViewController ?: self, @selector(waitForRender)) boolValue];
179
+}
162
 
180
 
181
+- (void)setWaitForRender:(BOOL)waitForRender {
182
+    objc_setAssociatedObject(self, @selector(waitForRender), [NSNumber numberWithBool:waitForRender], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
183
+}
163
 
184
 
164
 @end
185
 @end

+ 5
- 1
lib/ios/Utils/UITabBarController+RNNUtils.h View File

2
 #import <UIKit/UIKit.h>
2
 #import <UIKit/UIKit.h>
3
 
3
 
4
 @interface UITabBarController (RNNUtils)
4
 @interface UITabBarController (RNNUtils)
5
+
5
 - (UIView *)getTabView:(int)tabIndex;
6
 - (UIView *)getTabView:(int)tabIndex;
6
 
7
 
7
 - (UIView *)getTabIcon:(int)tabIndex;
8
 - (UIView *)getTabIcon:(int)tabIndex;
8
-@end
9
+
10
+- (NSArray *)deselectedViewControllers;
11
+
12
+@end

+ 8
- 1
lib/ios/Utils/UITabBarController+RNNUtils.m View File

18
     UIView *tab = [self getTabView:tabIndex];
18
     UIView *tab = [self getTabView:tabIndex];
19
     return [tab findChildByClass:[UIImageView class]];
19
     return [tab findChildByClass:[UIImageView class]];
20
 }
20
 }
21
-@end
21
+
22
+- (NSArray *)deselectedViewControllers {
23
+    NSMutableArray* childViewControllers = [NSMutableArray arrayWithArray:self.childViewControllers];
24
+    [childViewControllers removeObject:self.selectedViewController];
25
+    return [NSArray arrayWithArray:childViewControllers];
26
+}
27
+
28
+@end

+ 74
- 13
playground/ios/NavigationTests/RNNCommandsHandlerTest.m View File

8
 #import <ReactNativeNavigation/RNNErrorHandler.h>
8
 #import <ReactNativeNavigation/RNNErrorHandler.h>
9
 #import <OCMock/OCMock.h>
9
 #import <OCMock/OCMock.h>
10
 #import "RNNLayoutManager.h"
10
 #import "RNNLayoutManager.h"
11
+#import "RNNBottomTabsController.h"
12
+#import "BottomTabsAttachModeFactory.h"
11
 
13
 
12
 @interface MockUIApplication : NSObject
14
 @interface MockUIApplication : NSObject
13
 
15
 
63
 	self.eventEmmiter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
65
 	self.eventEmmiter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
64
 	self.overlayManager = [OCMockObject partialMockForObject:[RNNOverlayManager new]];
66
 	self.overlayManager = [OCMockObject partialMockForObject:[RNNOverlayManager new]];
65
 	self.modalManager = [OCMockObject partialMockForObject:[RNNModalManager new]];
67
 	self.modalManager = [OCMockObject partialMockForObject:[RNNModalManager new]];
66
-	self.controllerFactory = [OCMockObject partialMockForObject:[[RNNControllerFactory alloc] initWithRootViewCreator:nil eventEmitter:self.eventEmmiter store:nil componentRegistry:nil andBridge:nil]];
68
+	self.controllerFactory = [OCMockObject partialMockForObject:[[RNNControllerFactory alloc] initWithRootViewCreator:nil eventEmitter:self.eventEmmiter store:nil componentRegistry:nil andBridge:nil bottomTabsAttachModeFactory:[BottomTabsAttachModeFactory new]]];
67
 	self.uut = [[RNNCommandsHandler alloc] initWithControllerFactory:self.controllerFactory eventEmitter:self.eventEmmiter stackManager:[RNNNavigationStackManager new] modalManager:self.modalManager overlayManager:self.overlayManager mainWindow:_mainWindow];
69
 	self.uut = [[RNNCommandsHandler alloc] initWithControllerFactory:self.controllerFactory eventEmitter:self.eventEmmiter stackManager:[RNNNavigationStackManager new] modalManager:self.modalManager overlayManager:self.overlayManager mainWindow:_mainWindow];
68
-	self.vc1 = [RNNComponentViewController new];
69
-	self.vc2 = [RNNComponentViewController new];
70
-	self.vc3 = [RNNComponentViewController new];
70
+	self.vc1 = self.generateComponent;
71
+	self.vc2 = self.generateComponent;
72
+	self.vc3 = self.generateComponent;
71
 	_nvc = [[MockUINavigationController alloc] init];
73
 	_nvc = [[MockUINavigationController alloc] init];
72
 	[_nvc setViewControllers:@[self.vc1, self.vc2, self.vc3]];
74
 	[_nvc setViewControllers:@[self.vc1, self.vc2, self.vc3]];
73
 	OCMStub([self.sharedApplication keyWindow]).andReturn(self.mainWindow);
75
 	OCMStub([self.sharedApplication keyWindow]).andReturn(self.mainWindow);
74
 }
76
 }
75
 
77
 
78
+- (RNNComponentViewController *)generateComponent {
79
+	return [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:[[RNNTestRootViewCreator alloc] init] eventEmitter:nil presenter:[RNNComponentPresenter new] options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil];
80
+}
76
 
81
 
77
 - (void)testAssertReadyForEachMethodThrowsExceptoins {
82
 - (void)testAssertReadyForEachMethodThrowsExceptoins {
78
 	NSArray* methods = [self getPublicMethodNamesForObject:self.uut];
83
 	NSArray* methods = [self getPublicMethodNamesForObject:self.uut];
182
 
187
 
183
 - (void)testShowOverlay_withCreatedLayout {
188
 - (void)testShowOverlay_withCreatedLayout {
184
 	[self.uut setReadyToReceiveCommands:true];
189
 	[self.uut setReadyToReceiveCommands:true];
185
-	UIViewController* layoutVC = [RNNComponentViewController new];
190
+	UIViewController* layoutVC = self.generateComponent;
186
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(layoutVC);
191
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(layoutVC);
187
 	
192
 	
188
 	[[self.overlayManager expect] showOverlayWindow:[OCMArg any]];
193
 	[[self.overlayManager expect] showOverlayWindow:[OCMArg any]];
264
 	[self.uut setReadyToReceiveCommands:true];
269
 	[self.uut setReadyToReceiveCommands:true];
265
 	id classMock = OCMClassMock([RNNLayoutManager class]);
270
 	id classMock = OCMClassMock([RNNLayoutManager class]);
266
 	OCMStub(ClassMethod([classMock findComponentForId:@"vc1"])).andReturn(_nvc);
271
 	OCMStub(ClassMethod([classMock findComponentForId:@"vc1"])).andReturn(_nvc);
272
+	self.vc2.options.animations.setStackRoot.enable = [[Bool alloc] initWithBOOL:NO];
267
 	
273
 	
268
 	[self.uut setStackRoot:@"vc1" commandId:@"" children:nil completion:^{
274
 	[self.uut setStackRoot:@"vc1" commandId:@"" children:nil completion:^{
269
-		
275
+
270
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
276
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
271
 		
277
 		
272
 	}];
278
 	}];
281
 	OCMStub(ClassMethod([classMock findComponentForId:@"vc1"])).andReturn(_nvc);
287
 	OCMStub(ClassMethod([classMock findComponentForId:@"vc1"])).andReturn(_nvc);
282
 	OCMStub([self.controllerFactory createChildrenLayout:[OCMArg any]]).andReturn(newViewControllers);
288
 	OCMStub([self.controllerFactory createChildrenLayout:[OCMArg any]]).andReturn(newViewControllers);
283
 	[self.uut setReadyToReceiveCommands:true];
289
 	[self.uut setReadyToReceiveCommands:true];
290
+	
291
+	_vc3.options.animations.setStackRoot.enable = [[Bool alloc] initWithBOOL:NO];
284
 	[self.uut setStackRoot:@"vc1" commandId:@"" children:nil completion:^{
292
 	[self.uut setStackRoot:@"vc1" commandId:@"" children:nil completion:^{
285
-		
293
+	
286
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
294
 	} rejection:^(NSString *code, NSString *message, NSError *error) {
287
 		
295
 		
288
 	}];
296
 	}];
302
 		
310
 		
303
 	}];
311
 	}];
304
 	
312
 	
305
-	[[vc1Mock expect] renderTreeAndWait:NO perform:[OCMArg any]];
306
-	[[vc2Mock expect] renderTreeAndWait:NO perform:[OCMArg any]];
313
+	[[vc1Mock expect] render];
314
+	[[vc2Mock expect] render];
307
 }
315
 }
308
 
316
 
309
 - (void)testSetStackRoot_waitForRender {
317
 - (void)testSetStackRoot_waitForRender {
322
 		
330
 		
323
 	}];
331
 	}];
324
 	
332
 	
325
-	[[vc1Mock expect] renderTreeAndWait:NO perform:[OCMArg any]];
326
-	[[vc2Mock expect] renderTreeAndWait:YES perform:[OCMArg any]];
333
+	[[vc1Mock expect] render];
334
+	[[vc2Mock expect] render];
327
 }
335
 }
328
 
336
 
329
 - (void)testSetRoot_waitForRenderTrue {
337
 - (void)testSetRoot_waitForRenderTrue {
334
 	id mockedVC = [OCMockObject partialMockForObject:self.vc1];
342
 	id mockedVC = [OCMockObject partialMockForObject:self.vc1];
335
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(mockedVC);
343
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(mockedVC);
336
 	
344
 	
337
-	[[mockedVC expect] renderTreeAndWait:YES perform:[OCMArg any]];
345
+	[[mockedVC expect] render];
338
 	[self.uut setRoot:@{} commandId:@"" completion:^{}];
346
 	[self.uut setRoot:@{} commandId:@"" completion:^{}];
339
 	[mockedVC verify];
347
 	[mockedVC verify];
340
 }
348
 }
347
 	id mockedVC = [OCMockObject partialMockForObject:self.vc1];
355
 	id mockedVC = [OCMockObject partialMockForObject:self.vc1];
348
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(mockedVC);
356
 	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(mockedVC);
349
 	
357
 	
350
-	[[mockedVC expect] renderTreeAndWait:NO perform:[OCMArg any]];
358
+	[[mockedVC expect] render];
351
 	[self.uut setRoot:@{} commandId:@"" completion:^{}];
359
 	[self.uut setRoot:@{} commandId:@"" completion:^{}];
352
 	[mockedVC verify];
360
 	[mockedVC verify];
353
 }
361
 }
354
 
362
 
363
+- (void)testSetRoot_withBottomTabsAttachModeTogether {
364
+	[self.uut setReadyToReceiveCommands:true];
365
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initEmptyOptions];
366
+	options.bottomTabs.tabsAttachMode = [[BottomTabsAttachMode alloc] initWithValue:@"together"];
367
+	options.animations.setRoot.waitForRender = [[Bool alloc] initWithBOOL:YES];
368
+
369
+	BottomTabsBaseAttacher* attacher = [[[BottomTabsAttachModeFactory alloc] initWithDefaultOptions:nil] fromOptions:options];
370
+	RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] eventEmitter:_eventEmmiter childViewControllers:@[_vc1, _vc2] bottomTabsAttacher:attacher];
371
+
372
+	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController);
373
+	
374
+	[self.uut setRoot:@{} commandId:@"" completion:^{}];
375
+	XCTAssertTrue(_vc1.isViewLoaded);
376
+	XCTAssertTrue(_vc2.isViewLoaded);
377
+}
378
+
379
+- (void)testSetRoot_withBottomTabsAttachModeOnSwitchToTab {
380
+	[self.uut setReadyToReceiveCommands:true];
381
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initEmptyOptions];
382
+	options.bottomTabs.tabsAttachMode = [[BottomTabsAttachMode alloc] initWithValue:@"onSwitchToTab"];
383
+	options.animations.setRoot.waitForRender = [[Bool alloc] initWithBOOL:YES];
384
+	
385
+	BottomTabsBaseAttacher* attacher = [[[BottomTabsAttachModeFactory alloc] initWithDefaultOptions:nil] fromOptions:options];
386
+	RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] eventEmitter:_eventEmmiter childViewControllers:@[_vc1, _vc2] bottomTabsAttacher:attacher];
387
+
388
+	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController);
389
+	
390
+	[self.uut setRoot:@{} commandId:@"" completion:^{}];
391
+	XCTAssertTrue(_vc1.isViewLoaded);
392
+	XCTAssertFalse(_vc2.isViewLoaded);
393
+	[tabBarController setSelectedIndex:1];
394
+	XCTAssertTrue(_vc2.isViewLoaded);
395
+}
396
+
397
+- (void)testSetRoot_withBottomTabsAttachModeAfterInitialTab {
398
+	[self.uut setReadyToReceiveCommands:true];
399
+	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initEmptyOptions];
400
+	options.bottomTabs.tabsAttachMode = [[BottomTabsAttachMode alloc] initWithValue:@"afterInitialTab"];
401
+	options.animations.setRoot.waitForRender = [[Bool alloc] initWithBOOL:YES];
402
+
403
+	BottomTabsBaseAttacher* attacher = [[[BottomTabsAttachModeFactory alloc] initWithDefaultOptions:nil] fromOptions:options];
404
+	RNNBottomTabsController* tabBarController = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:options defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:[RNNBasePresenter new] eventEmitter:_eventEmmiter childViewControllers:@[_vc1, _vc2] bottomTabsAttacher:attacher];
405
+
406
+	OCMStub([self.controllerFactory createLayout:[OCMArg any]]).andReturn(tabBarController);
407
+
408
+	[self.uut setRoot:@{} commandId:@"" completion:^{
409
+		XCTAssertFalse(self->_vc2.isViewLoaded);
410
+	}];
411
+
412
+	XCTAssertTrue(_vc1.isViewLoaded);
413
+	XCTAssertTrue(_vc2.isViewLoaded);
414
+}
415
+
355
 - (void)testShowModal_shouldShowAnimated {
416
 - (void)testShowModal_shouldShowAnimated {
356
 	[self.uut setReadyToReceiveCommands:true];
417
 	[self.uut setReadyToReceiveCommands:true];
357
 	self.vc1.options = [[RNNNavigationOptions alloc] initEmptyOptions];
418
 	self.vc1.options = [[RNNNavigationOptions alloc] initEmptyOptions];

+ 4
- 2
playground/ios/NavigationTests/RNNControllerFactoryTest.m View File

8
 #import "RNNBottomTabsController.h"
8
 #import "RNNBottomTabsController.h"
9
 #import "RNNTopTabsViewController.h"
9
 #import "RNNTopTabsViewController.h"
10
 #import "RNNSplitViewController.h"
10
 #import "RNNSplitViewController.h"
11
+#import "RNNExternalViewController.h"
11
 
12
 
12
 @interface RNNControllerFactoryTest : XCTestCase
13
 @interface RNNControllerFactoryTest : XCTestCase
13
 
14
 
23
 	[super setUp];
24
 	[super setUp];
24
 	self.creator = nil;
25
 	self.creator = nil;
25
 	self.store = [RNNExternalComponentStore new];
26
 	self.store = [RNNExternalComponentStore new];
26
-	self.factory = [[RNNControllerFactory alloc] initWithRootViewCreator:self.creator eventEmitter:nil store:self.store componentRegistry:nil andBridge:nil];
27
+	self.factory = [[RNNControllerFactory alloc] initWithRootViewCreator:self.creator eventEmitter:nil store:self.store componentRegistry:nil andBridge:nil bottomTabsAttachModeFactory:[BottomTabsAttachModeFactory new]];
27
 }
28
 }
28
 
29
 
29
 - (void)tearDown {
30
 - (void)tearDown {
53
 							  @"data": @{@"name": @"externalComponent"},
54
 							  @"data": @{@"name": @"externalComponent"},
54
 							  @"children": @[]};
55
 							  @"children": @[]};
55
 	id ans = [self.factory createLayout:layout];
56
 	id ans = [self.factory createLayout:layout];
56
-	XCTAssertTrue([ans isMemberOfClass:[RNNComponentViewController class]]);
57
+	XCTAssertTrue([ans isKindOfClass:[RNNComponentViewController class]]);
58
+	XCTAssertTrue([ans isMemberOfClass:[RNNExternalViewController class]]);
57
 }
59
 }
58
 
60
 
59
 - (void)testCreateLayout_ComponentStackLayout {
61
 - (void)testCreateLayout_ComponentStackLayout {

+ 10
- 3
playground/ios/NavigationTests/RNNSideMenuControllerTest.m View File

1
 #import <XCTest/XCTest.h>
1
 #import <XCTest/XCTest.h>
2
 #import "RNNSideMenuController.h"
2
 #import "RNNSideMenuController.h"
3
 #import "RNNComponentViewController.h"
3
 #import "RNNComponentViewController.h"
4
+#import "RNNTestRootViewCreator.h"
4
 
5
 
5
 @interface RNNSideMenuControllerTest : XCTestCase
6
 @interface RNNSideMenuControllerTest : XCTestCase
6
 @property (nonatomic, strong) RNNSideMenuController *uut;
7
 @property (nonatomic, strong) RNNSideMenuController *uut;
8
+@property (nonatomic, strong) RNNTestRootViewCreator *creator;
7
 @property (nonatomic, strong) RNNSideMenuChildVC *centerVC;
9
 @property (nonatomic, strong) RNNSideMenuChildVC *centerVC;
8
 @property (nonatomic, strong) RNNSideMenuChildVC *leftVC;
10
 @property (nonatomic, strong) RNNSideMenuChildVC *leftVC;
9
 @property (nonatomic, strong) RNNSideMenuChildVC *rightVC;
11
 @property (nonatomic, strong) RNNSideMenuChildVC *rightVC;
13
 
15
 
14
 - (void)setUp {
16
 - (void)setUp {
15
     [super setUp];
17
     [super setUp];
16
-	_leftVC = [[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:[RNNComponentViewController new] type:RNNSideMenuChildTypeLeft];
17
-	_rightVC = [[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:[RNNComponentViewController new] type:RNNSideMenuChildTypeRight];
18
-	_centerVC =[[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:[RNNComponentViewController new] type:RNNSideMenuChildTypeCenter];
18
+	_creator = [[RNNTestRootViewCreator alloc] init];
19
+	_leftVC = [[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:self.generateComponent type:RNNSideMenuChildTypeLeft];
20
+	_rightVC = [[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:self.generateComponent type:RNNSideMenuChildTypeRight];
21
+	_centerVC =[[RNNSideMenuChildVC alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:nil eventEmitter:nil childViewController:self.generateComponent type:RNNSideMenuChildTypeCenter];
19
 	self.uut = [[RNNSideMenuController alloc] initWithLayoutInfo:nil creator:nil childViewControllers:@[_leftVC, _centerVC, _rightVC] options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:nil eventEmitter:nil];
22
 	self.uut = [[RNNSideMenuController alloc] initWithLayoutInfo:nil creator:nil childViewControllers:@[_leftVC, _centerVC, _rightVC] options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:nil eventEmitter:nil];
20
 }
23
 }
21
 
24
 
25
+- (RNNComponentViewController *)generateComponent {
26
+	return [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:_creator eventEmitter:nil presenter:[RNNComponentPresenter new] options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil];
27
+}
28
+
22
 - (void)testSetSideMenuWidthShouldUpdateLeftReactViewFrameWidth {
29
 - (void)testSetSideMenuWidthShouldUpdateLeftReactViewFrameWidth {
23
 	[self.uut side:MMDrawerSideLeft width:100];
30
 	[self.uut side:MMDrawerSideLeft width:100];
24
 	XCTAssertEqual(self.uut.left.child.view.frame.size.width, 100.f);
31
 	XCTAssertEqual(self.uut.left.child.view.frame.size.width, 100.f);

+ 1
- 1
playground/ios/NavigationTests/RNNTestRootViewCreator.h View File

1
 #import <Foundation/Foundation.h>
1
 #import <Foundation/Foundation.h>
2
-#import <ReactNativeNavigation/RNNComponentViewCreator.h>
2
+#import "RNNComponentViewCreator.h"
3
 
3
 
4
 @interface RNNTestRootViewCreator : NSObject <RNNComponentViewCreator>
4
 @interface RNNTestRootViewCreator : NSObject <RNNComponentViewCreator>
5
 
5
 

+ 2
- 2
playground/ios/Podfile.lock View File

220
     - ReactCommon/jscallinvoker (= 0.61.4)
220
     - ReactCommon/jscallinvoker (= 0.61.4)
221
   - ReactNativeKeyboardTrackingView (5.6.1):
221
   - ReactNativeKeyboardTrackingView (5.6.1):
222
     - React
222
     - React
223
-  - ReactNativeNavigation (4.0.2):
223
+  - ReactNativeNavigation (4.0.4):
224
     - React
224
     - React
225
   - Yoga (1.14.0)
225
   - Yoga (1.14.0)
226
 
226
 
346
   React-RCTVibration: 0f76400ee3cec6edb9c125da49fed279340d145a
346
   React-RCTVibration: 0f76400ee3cec6edb9c125da49fed279340d145a
347
   ReactCommon: a6a294e7028ed67b926d29551aa9394fd989c24c
347
   ReactCommon: a6a294e7028ed67b926d29551aa9394fd989c24c
348
   ReactNativeKeyboardTrackingView: a240a6a0dba852bb107109a7ec7e98b884055977
348
   ReactNativeKeyboardTrackingView: a240a6a0dba852bb107109a7ec7e98b884055977
349
-  ReactNativeNavigation: f3da2b103f01bc576bbb1a41df67486788dcf6af
349
+  ReactNativeNavigation: bf2951e30fb873b3ed1e736419c38ed1efe0f6c2
350
   Yoga: ba3d99dbee6c15ea6bbe3783d1f0cb1ffb79af0f
350
   Yoga: ba3d99dbee6c15ea6bbe3783d1f0cb1ffb79af0f
351
 
351
 
352
 PODFILE CHECKSUM: 8a6eee15d75935b9144e5228ce8fa2a5b98079e7
352
 PODFILE CHECKSUM: 8a6eee15d75935b9144e5228ce8fa2a5b98079e7

+ 6
- 0
playground/ios/playground.xcodeproj/project.pbxproj View File

43
 		E58D26602385888C003F36BA /* RNNModalManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26432385888C003F36BA /* RNNModalManagerTest.m */; };
43
 		E58D26602385888C003F36BA /* RNNModalManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26432385888C003F36BA /* RNNModalManagerTest.m */; };
44
 		E58D26612385888C003F36BA /* RNNTestNoColor.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26452385888C003F36BA /* RNNTestNoColor.m */; };
44
 		E58D26612385888C003F36BA /* RNNTestNoColor.m in Sources */ = {isa = PBXBuildFile; fileRef = E58D26452385888C003F36BA /* RNNTestNoColor.m */; };
45
 		EFC0DF770EBAEFC23D0CB155 /* Pods_NavigationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84E32151E3A71C2B7328BCB4 /* Pods_NavigationTests.framework */; };
45
 		EFC0DF770EBAEFC23D0CB155 /* Pods_NavigationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84E32151E3A71C2B7328BCB4 /* Pods_NavigationTests.framework */; };
46
+		FE548D2471FE535CFCE8B113 /* Pods_playground.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50364D69238E7ECC000E62A2 /* Pods_playground.framework */; };
46
 /* End PBXBuildFile section */
47
 /* End PBXBuildFile section */
47
 
48
 
48
 /* Begin PBXContainerItemProxy section */
49
 /* Begin PBXContainerItemProxy section */
65
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
66
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
66
 		4259AF43A23D928FE78B4A3A /* Pods-NavigationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NavigationTests.debug.xcconfig"; path = "Target Support Files/Pods-NavigationTests/Pods-NavigationTests.debug.xcconfig"; sourceTree = "<group>"; };
67
 		4259AF43A23D928FE78B4A3A /* Pods-NavigationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NavigationTests.debug.xcconfig"; path = "Target Support Files/Pods-NavigationTests/Pods-NavigationTests.debug.xcconfig"; sourceTree = "<group>"; };
67
 		4A3340545EAAF11C1F146864 /* Pods_playground.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_playground.framework; sourceTree = BUILT_PRODUCTS_DIR; };
68
 		4A3340545EAAF11C1F146864 /* Pods_playground.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_playground.framework; sourceTree = BUILT_PRODUCTS_DIR; };
69
+		50364D69238E7ECC000E62A2 /* Pods_playground.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_playground.framework; sourceTree = BUILT_PRODUCTS_DIR; };
70
+		50364D6B238E7F0A000E62A2 /* ReactNativeNavigation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ReactNativeNavigation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
68
 		50451D33204451A800695F00 /* RNNCustomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNNCustomViewController.h; path = ../../../lib/ios/RNNCustomViewController.h; sourceTree = "<group>"; };
71
 		50451D33204451A800695F00 /* RNNCustomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNNCustomViewController.h; path = ../../../lib/ios/RNNCustomViewController.h; sourceTree = "<group>"; };
69
 		50451D34204451A800695F00 /* RNNCustomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNNCustomViewController.m; path = ../../../lib/ios/RNNCustomViewController.m; sourceTree = "<group>"; };
72
 		50451D34204451A800695F00 /* RNNCustomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNNCustomViewController.m; path = ../../../lib/ios/RNNCustomViewController.m; sourceTree = "<group>"; };
70
 		7F8E255E2E08F6ECE7DF6FE3 /* Pods-playground.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-playground.release.xcconfig"; path = "Target Support Files/Pods-playground/Pods-playground.release.xcconfig"; sourceTree = "<group>"; };
73
 		7F8E255E2E08F6ECE7DF6FE3 /* Pods-playground.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-playground.release.xcconfig"; path = "Target Support Files/Pods-playground/Pods-playground.release.xcconfig"; sourceTree = "<group>"; };
114
 			files = (
117
 			files = (
115
 				E5046080227748EA00212BD8 /* JavaScriptCore.framework in Frameworks */,
118
 				E5046080227748EA00212BD8 /* JavaScriptCore.framework in Frameworks */,
116
 				9D204F3DC4FBCD81583BF99F /* Pods_playground.framework in Frameworks */,
119
 				9D204F3DC4FBCD81583BF99F /* Pods_playground.framework in Frameworks */,
120
+				FE548D2471FE535CFCE8B113 /* Pods_playground.framework in Frameworks */,
117
 			);
121
 			);
118
 			runOnlyForDeploymentPostprocessing = 0;
122
 			runOnlyForDeploymentPostprocessing = 0;
119
 		};
123
 		};
188
 		E504607E227748E900212BD8 /* Frameworks */ = {
192
 		E504607E227748E900212BD8 /* Frameworks */ = {
189
 			isa = PBXGroup;
193
 			isa = PBXGroup;
190
 			children = (
194
 			children = (
195
+				50364D6B238E7F0A000E62A2 /* ReactNativeNavigation.framework */,
196
+				50364D69238E7ECC000E62A2 /* Pods_playground.framework */,
191
 				E504607F227748EA00212BD8 /* JavaScriptCore.framework */,
197
 				E504607F227748EA00212BD8 /* JavaScriptCore.framework */,
192
 				4A3340545EAAF11C1F146864 /* Pods_playground.framework */,
198
 				4A3340545EAAF11C1F146864 /* Pods_playground.framework */,
193
 				84E32151E3A71C2B7328BCB4 /* Pods_NavigationTests.framework */,
199
 				84E32151E3A71C2B7328BCB4 /* Pods_NavigationTests.framework */,

+ 14
- 0
playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme View File

6
       parallelizeBuildables = "NO"
6
       parallelizeBuildables = "NO"
7
       buildImplicitDependencies = "YES">
7
       buildImplicitDependencies = "YES">
8
       <BuildActionEntries>
8
       <BuildActionEntries>
9
+         <BuildActionEntry
10
+            buildForTesting = "YES"
11
+            buildForRunning = "YES"
12
+            buildForProfiling = "YES"
13
+            buildForArchiving = "YES"
14
+            buildForAnalyzing = "YES">
15
+            <BuildableReference
16
+               BuildableIdentifier = "primary"
17
+               BlueprintIdentifier = "6ADCF369490C694BEBF31C5B4517D035"
18
+               BuildableName = "ReactNativeNavigation.framework"
19
+               BlueprintName = "ReactNativeNavigation"
20
+               ReferencedContainer = "container:Pods/Pods.xcodeproj">
21
+            </BuildableReference>
22
+         </BuildActionEntry>
9
          <BuildActionEntry
23
          <BuildActionEntry
10
             buildForTesting = "YES"
24
             buildForTesting = "YES"
11
             buildForRunning = "YES"
25
             buildForRunning = "YES"

+ 1
- 1
playground/src/commons/Options.js View File

60
 
60
 
61
 module.exports = {
61
 module.exports = {
62
   setDefaultOptions
62
   setDefaultOptions
63
-}
63
+}