Browse Source

V2 custom controller (#2784)

* custom viewController support

* native component support and e2e

* custom viewController support

* native component support and e2e

* unit test fix
yogevbd 6 years ago
parent
commit
eb9142a3e1
No account linked to committer's email address

+ 6
- 0
e2e/ScreenStack.test.js View File

93
     await elementById(testIDs.POP_BUTTON).tap();
93
     await elementById(testIDs.POP_BUTTON).tap();
94
     await expect(elementByLabel('Screen 1')).toBeVisible();
94
     await expect(elementByLabel('Screen 1')).toBeVisible();
95
   });
95
   });
96
+
97
+  it(':ios: push native component with options', async () => {
98
+    await elementById(testIDs.PUSH_NATIVE_COMPONENT_BUTTON).tap();
99
+    await expect(elementById('TestLabel')).toBeVisible();
100
+    await expect(elementById(testIDs.TOP_BAR_ELEMENT)).toBeVisible();
101
+  });
96
 });
102
 });

+ 13
- 7
lib/ios/RNNControllerFactory.m View File

43
 	
43
 	
44
 	UIViewController<RNNRootViewProtocol> *result;
44
 	UIViewController<RNNRootViewProtocol> *result;
45
 	
45
 	
46
-	if ( node.isComponent) {
47
-		result = [self createComponent:node];
46
+	if (node.isComponent) {
47
+		result = [self createComponent:node nativeComponent:NO];
48
 	}
48
 	}
49
 	
49
 	
50
 	else if (node.isStack)	{
50
 	else if (node.isStack)	{
70
 	else if (node.isSideMenuLeft) {
70
 	else if (node.isSideMenuLeft) {
71
 		result = [self createSideMenuChild:node type:RNNSideMenuChildTypeLeft];
71
 		result = [self createSideMenuChild:node type:RNNSideMenuChildTypeLeft];
72
 	}
72
 	}
73
+	
73
 	else if (node.isSideMenuRight) {
74
 	else if (node.isSideMenuRight) {
74
 		result = [self createSideMenuChild:node type:RNNSideMenuChildTypeRight];
75
 		result = [self createSideMenuChild:node type:RNNSideMenuChildTypeRight];
75
 	}
76
 	}
76
 	
77
 	
78
+	else if ( node.isNativeComponent) {
79
+		result = [self createComponent:node nativeComponent:YES];
80
+	}
81
+	
77
 	if (!result) {
82
 	if (!result) {
78
 		@throw [NSException exceptionWithName:@"UnknownControllerType" reason:[@"Unknown controller type " stringByAppendingString:node.type] userInfo:nil];
83
 		@throw [NSException exceptionWithName:@"UnknownControllerType" reason:[@"Unknown controller type " stringByAppendingString:node.type] userInfo:nil];
79
 	}
84
 	}
83
 	return result;
88
 	return result;
84
 }
89
 }
85
 
90
 
86
-- (UIViewController<RNNRootViewProtocol> *)createComponent:(RNNLayoutNode*)node {
91
+- (UIViewController<RNNRootViewProtocol> *)createComponent:(RNNLayoutNode*)node nativeComponent:(BOOL)nativeComponent {
87
 	NSString* name = node.data[@"name"];
92
 	NSString* name = node.data[@"name"];
88
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
93
 	RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
89
 	options.defaultOptions = _defaultOptions;
94
 	options.defaultOptions = _defaultOptions;
90
 	NSString* componentId = node.nodeId;
95
 	NSString* componentId = node.nodeId;
91
-	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter];
92
-	CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
93
-	[_bridge.uiManager setAvailableSize:availableSize forRootView:component.view];
94
-	
96
+	RNNRootViewController* component = [[RNNRootViewController alloc] initWithName:name withOptions:options withComponentId:componentId rootViewCreator:_creator eventEmitter:_eventEmitter isNativeComponent:nativeComponent];
97
+	if (!component.isCustomViewController) {
98
+		CGSize availableSize = UIApplication.sharedApplication.delegate.window.bounds.size;
99
+		[_bridge.uiManager setAvailableSize:availableSize forRootView:component.view];
100
+	}
95
 	return component;
101
 	return component;
96
 }
102
 }
97
 
103
 

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

1
+#import <UIKit/UIKit.h>
2
+
3
+@interface RNNCustomViewController : UIViewController
4
+
5
+@end

+ 18
- 0
lib/ios/RNNCustomViewController.m View File

1
+#import "RNNCustomViewController.h"
2
+
3
+@implementation RNNCustomViewController
4
+
5
+- (void)viewDidLoad {
6
+    [super viewDidLoad];
7
+	[self addTestLabel];
8
+}
9
+
10
+- (void)addTestLabel {
11
+	UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
12
+	label.center = self.view.center;
13
+	label.text = @"Test label";
14
+	label.accessibilityIdentifier = @"TestLabel";
15
+	[self.view addSubview:label];
16
+}
17
+
18
+@end

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

12
 +(instancetype)create:(NSDictionary *)json;
12
 +(instancetype)create:(NSDictionary *)json;
13
 
13
 
14
 -(BOOL)isComponent;
14
 -(BOOL)isComponent;
15
+-(BOOL)isNativeComponent;
15
 -(BOOL)isStack;
16
 -(BOOL)isStack;
16
 -(BOOL)isTabs;
17
 -(BOOL)isTabs;
17
 -(BOOL)isTopTabs;
18
 -(BOOL)isTopTabs;

+ 4
- 0
lib/ios/RNNLayoutNode.m View File

17
 {
17
 {
18
 	return [self.type isEqualToString:@"Component"];
18
 	return [self.type isEqualToString:@"Component"];
19
 }
19
 }
20
+-(BOOL)isNativeComponent
21
+{
22
+	return [self.type isEqualToString:@"NativeComponent"];
23
+}
20
 -(BOOL)isStack
24
 -(BOOL)isStack
21
 {
25
 {
22
 	return [self.type isEqualToString:@"Stack"];
26
 	return [self.type isEqualToString:@"Stack"];

+ 5
- 1
lib/ios/RNNNavigationStackManager.m View File

18
 -(void)push:(UIViewController<RNNRootViewProtocol> *)newTop onTop:(NSString *)componentId completion:(RNNTransitionCompletionBlock)completion {
18
 -(void)push:(UIViewController<RNNRootViewProtocol> *)newTop onTop:(NSString *)componentId completion:(RNNTransitionCompletionBlock)completion {
19
 	UIViewController *vc = [_store findComponentForId:componentId];
19
 	UIViewController *vc = [_store findComponentForId:componentId];
20
 	[self preparePush:newTop onTopVC:vc completion:completion];
20
 	[self preparePush:newTop onTopVC:vc completion:completion];
21
-	[self waitForContentToAppearAndThen:@selector(pushAfterLoad:)];
21
+	if ([newTop isCustomViewController]) {
22
+		[self pushAfterLoad:nil];
23
+	} else {
24
+		[self waitForContentToAppearAndThen:@selector(pushAfterLoad:)];
25
+	}
22
 }
26
 }
23
 
27
 
24
 -(void)preparePush:(UIViewController<RNNRootViewProtocol> *)newTop onTopVC:(UIViewController*)vc completion:(RNNTransitionCompletionBlock)completion {
28
 -(void)preparePush:(UIViewController<RNNRootViewProtocol> *)newTop onTopVC:(UIViewController*)vc completion:(RNNTransitionCompletionBlock)completion {

+ 2
- 1
lib/ios/RNNRootViewController.h View File

22
 				withOptions:(RNNNavigationOptions*)options
22
 				withOptions:(RNNNavigationOptions*)options
23
 			withComponentId:(NSString*)componentId
23
 			withComponentId:(NSString*)componentId
24
 			rootViewCreator:(id<RNNRootViewCreator>)creator
24
 			rootViewCreator:(id<RNNRootViewCreator>)creator
25
-			   eventEmitter:(RNNEventEmitter*)eventEmitter;
25
+			   eventEmitter:(RNNEventEmitter*)eventEmitter
26
+		  isNativeComponent:(BOOL)isNativeComponent;
26
 
27
 
27
 
28
 
28
 -(void)applyTabBarItem;
29
 -(void)applyTabBarItem;

+ 36
- 2
lib/ios/RNNRootViewController.m View File

7
 @interface RNNRootViewController()
7
 @interface RNNRootViewController()
8
 @property (nonatomic, strong) NSString* componentName;
8
 @property (nonatomic, strong) NSString* componentName;
9
 @property (nonatomic) BOOL _statusBarHidden;
9
 @property (nonatomic) BOOL _statusBarHidden;
10
+@property (nonatomic) BOOL isNativeComponent;
10
 @end
11
 @end
11
 
12
 
12
 @implementation RNNRootViewController
13
 @implementation RNNRootViewController
15
 				withOptions:(RNNNavigationOptions*)options
16
 				withOptions:(RNNNavigationOptions*)options
16
 			withComponentId:(NSString*)componentId
17
 			withComponentId:(NSString*)componentId
17
 			rootViewCreator:(id<RNNRootViewCreator>)creator
18
 			rootViewCreator:(id<RNNRootViewCreator>)creator
18
-			   eventEmitter:(RNNEventEmitter*)eventEmitter {
19
+			   eventEmitter:(RNNEventEmitter*)eventEmitter
20
+		  isNativeComponent:(BOOL)isNativeComponent {
19
 	self = [super init];
21
 	self = [super init];
20
 	self.componentId = componentId;
22
 	self.componentId = componentId;
21
 	self.componentName = name;
23
 	self.componentName = name;
23
 	self.eventEmitter = eventEmitter;
25
 	self.eventEmitter = eventEmitter;
24
 	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.options.customTransition];
26
 	self.animator = [[RNNAnimator alloc] initWithTransitionOptions:self.options.customTransition];
25
 	self.creator = creator;
27
 	self.creator = creator;
26
-	self.view = [creator createRootView:self.componentName rootViewId:self.componentId];
28
+	self.isNativeComponent = isNativeComponent;
29
+	
30
+	if (self.isNativeComponent) {
31
+		[self addExternalVC:name];
32
+	} else {
33
+		self.view = [creator createRootView:self.componentName rootViewId:self.componentId];
34
+	}
27
 	
35
 	
28
 	[[NSNotificationCenter defaultCenter] addObserver:self
36
 	[[NSNotificationCenter defaultCenter] addObserver:self
29
 											 selector:@selector(onJsReload)
37
 											 selector:@selector(onJsReload)
90
 	return self.options.animated ? [self.options.animated boolValue] : YES;
98
 	return self.options.animated ? [self.options.animated boolValue] : YES;
91
 }
99
 }
92
 
100
 
101
+- (BOOL)isCustomViewController {
102
+	return self.isNativeComponent;
103
+}
104
+
93
 - (BOOL)prefersStatusBarHidden {
105
 - (BOOL)prefersStatusBarHidden {
94
 	if ([self.options.statusBarHidden boolValue]) {
106
 	if ([self.options.statusBarHidden boolValue]) {
95
 		return YES;
107
 		return YES;
143
 	[self.options.topTab applyOn:self];
155
 	[self.options.topTab applyOn:self];
144
 }
156
 }
145
 
157
 
158
+-(void)addExternalVC:(NSString*)className {
159
+	if (className != nil) {
160
+		Class class = NSClassFromString(className);
161
+		if (class != NULL) {
162
+			id obj = [[class alloc] init];
163
+			if (obj != nil && [obj isKindOfClass:[UIViewController class]]) {
164
+				UIViewController *viewController = (UIViewController*)obj;
165
+				[self addChildViewController:viewController];
166
+				self.view = [[UIView alloc] init];
167
+				self.view.backgroundColor = [UIColor whiteColor];
168
+				[self.view addSubview:viewController.view];
169
+			}
170
+			else {
171
+				NSLog(@"addExternalVC: could not create instance. Make sure that your class is a UIViewController whihc confirms to RCCExternalViewControllerProtocol");
172
+			}
173
+		}
174
+		else {
175
+			NSLog(@"addExternalVC: could not create class from string. Check that the proper class name wass passed in ExternalNativeScreenClass");
176
+		}
177
+	}
178
+}
179
+
146
 /**
180
 /**
147
  *	fix for #877, #878
181
  *	fix for #877, #878
148
  */
182
  */

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

4
 
4
 
5
 @optional
5
 @optional
6
 - (void)mergeOptions:(NSDictionary*)options;
6
 - (void)mergeOptions:(NSDictionary*)options;
7
+- (BOOL)isCustomViewController;
7
 
8
 
8
 @required
9
 @required
9
-
10
 - (BOOL)isCustomTransitioned;
10
 - (BOOL)isCustomTransitioned;
11
 - (BOOL)isAnimated;
11
 - (BOOL)isAnimated;
12
 
12
 

+ 2
- 1
lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m View File

68
 																withOptions:initialOptions
68
 																withOptions:initialOptions
69
 															withComponentId:@"componentId"
69
 															withComponentId:@"componentId"
70
 															rootViewCreator:[[RNNTestRootViewCreator alloc] init]
70
 															rootViewCreator:[[RNNTestRootViewCreator alloc] init]
71
-															   eventEmitter:nil];
71
+															   eventEmitter:nil
72
+														  isNativeComponent:NO];
72
 	RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
73
 	RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
73
 	[vc viewWillAppear:false];
74
 	[vc viewWillAppear:false];
74
 	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);
75
 	XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m View File

42
 	self.componentId = @"cntId";
42
 	self.componentId = @"cntId";
43
 	self.emitter = nil;
43
 	self.emitter = nil;
44
 	self.options = [RNNNavigationOptions new];
44
 	self.options = [RNNNavigationOptions new];
45
-	self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withComponentId:self.componentId rootViewCreator:self.creator eventEmitter:self.emitter];
45
+	self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withComponentId:self.componentId rootViewCreator:self.creator eventEmitter:self.emitter isNativeComponent:NO];
46
 }
46
 }
47
 
47
 
48
 -(void)testTopBarBackgroundColor_validColor{
48
 -(void)testTopBarBackgroundColor_validColor{

+ 18
- 1
lib/src/commands/LayoutTreeParser.test.ts View File

22
       });
22
       });
23
     });
23
     });
24
 
24
 
25
+    it('native component', () => {
26
+      expect(uut.parse(LayoutExamples.nativeComponent)).toEqual({
27
+        type: LayoutType.NativeComponent,
28
+        data: { name: 'MyReactComponent', options: LayoutExamples.options, passProps: LayoutExamples.passProps },
29
+        children: []
30
+      });
31
+    });
32
+
25
     it('pass props', () => {
33
     it('pass props', () => {
26
       const result = uut.parse({
34
       const result = uut.parse({
27
         component: {
35
         component: {
167
   }
175
   }
168
 };
176
 };
169
 
177
 
178
+const nativeComponent = {
179
+  nativeComponent: {
180
+    name: 'MyReactComponent',
181
+    options,
182
+    passProps
183
+  }
184
+};
185
+
170
 const stackWithTopBar = {
186
 const stackWithTopBar = {
171
   stack: {
187
   stack: {
172
     children: [
188
     children: [
269
   bottomTabs,
285
   bottomTabs,
270
   sideMenu,
286
   sideMenu,
271
   topTabs,
287
   topTabs,
272
-  complexLayout
288
+  complexLayout,
289
+  nativeComponent
273
 };
290
 };

+ 11
- 0
lib/src/commands/LayoutTreeParser.ts View File

18
       return this._stack(api.stack);
18
       return this._stack(api.stack);
19
     } else if (api.component) {
19
     } else if (api.component) {
20
       return this._component(api.component);
20
       return this._component(api.component);
21
+    } else if (api.nativeComponent) {
22
+      return this._nativeComponent(api.nativeComponent);
21
     }
23
     }
22
     throw new Error(`unknown LayoutType "${_.keys(api)}"`);
24
     throw new Error(`unknown LayoutType "${_.keys(api)}"`);
23
   }
25
   }
96
       children: []
98
       children: []
97
     };
99
     };
98
   }
100
   }
101
+
102
+  _nativeComponent(api): LayoutNode {
103
+    return {
104
+      id: api.id,
105
+      type: LayoutType.NativeComponent,
106
+      data: { name: api.name, options: api.options, passProps: api.passProps },
107
+      children: []
108
+    };
109
+  }
99
 }
110
 }

+ 2
- 1
lib/src/commands/LayoutType.ts View File

6
   SideMenuCenter = 'SideMenuCenter',
6
   SideMenuCenter = 'SideMenuCenter',
7
   SideMenuLeft = 'SideMenuLeft',
7
   SideMenuLeft = 'SideMenuLeft',
8
   SideMenuRight = 'SideMenuRight',
8
   SideMenuRight = 'SideMenuRight',
9
-  TopTabs = 'TopTabs'
9
+  TopTabs = 'TopTabs',
10
+  NativeComponent = 'NativeComponent'
10
 }
11
 }
11
 
12
 
12
 export function isLayoutType(name: string): boolean {
13
 export function isLayoutType(name: string): boolean {

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

11
 		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
11
 		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
12
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
12
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
13
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
14
+		50451D35204451A900695F00 /* RNNCustomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50451D34204451A800695F00 /* RNNCustomViewController.m */; };
14
 		7B8F30491E84151300110AEC /* libcxxreact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FDE1E840F3600110AEC /* libcxxreact.a */; };
15
 		7B8F30491E84151300110AEC /* libcxxreact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FDE1E840F3600110AEC /* libcxxreact.a */; };
15
 		7B8F304A1E84151300110AEC /* libjschelpers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FE21E840F3600110AEC /* libjschelpers.a */; };
16
 		7B8F304A1E84151300110AEC /* libjschelpers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FE21E840F3600110AEC /* libjschelpers.a */; };
16
 		7B8F304B1E84151300110AEC /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FFA1E8411A800110AEC /* libRCTActionSheet.a */; };
17
 		7B8F304B1E84151300110AEC /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8F2FFA1E8411A800110AEC /* libRCTActionSheet.a */; };
270
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
271
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
271
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
272
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
272
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
273
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
274
+		50451D33204451A800695F00 /* RNNCustomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNNCustomViewController.h; path = ../../../lib/ios/RNNCustomViewController.h; sourceTree = "<group>"; };
275
+		50451D34204451A800695F00 /* RNNCustomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNNCustomViewController.m; path = ../../../lib/ios/RNNCustomViewController.m; sourceTree = "<group>"; };
273
 		7B8F2FC41E840F1A00110AEC /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = ../../lib/ios/ReactNativeNavigation.xcodeproj; sourceTree = "<group>"; };
276
 		7B8F2FC41E840F1A00110AEC /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = ../../lib/ios/ReactNativeNavigation.xcodeproj; sourceTree = "<group>"; };
274
 		7B8F2FCA1E840F3600110AEC /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
277
 		7B8F2FCA1E840F3600110AEC /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
275
 		7B8F2FE51E840F6700110AEC /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
278
 		7B8F2FE51E840F6700110AEC /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
315
 			children = (
318
 			children = (
316
 				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
319
 				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
317
 				13B07FB01A68108700A75B9A /* AppDelegate.m */,
320
 				13B07FB01A68108700A75B9A /* AppDelegate.m */,
321
+				50451D33204451A800695F00 /* RNNCustomViewController.h */,
322
+				50451D34204451A800695F00 /* RNNCustomViewController.m */,
318
 				13B07FB51A68108700A75B9A /* Images.xcassets */,
323
 				13B07FB51A68108700A75B9A /* Images.xcassets */,
319
 				13B07FB61A68108700A75B9A /* Info.plist */,
324
 				13B07FB61A68108700A75B9A /* Info.plist */,
320
 				13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
325
 				13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
850
 			isa = PBXSourcesBuildPhase;
855
 			isa = PBXSourcesBuildPhase;
851
 			buildActionMask = 2147483647;
856
 			buildActionMask = 2147483647;
852
 			files = (
857
 			files = (
858
+				50451D35204451A900695F00 /* RNNCustomViewController.m in Sources */,
853
 				13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
859
 				13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
854
 				13B07FC11A68108700A75B9A /* main.m in Sources */,
860
 				13B07FC11A68108700A75B9A /* main.m in Sources */,
855
 			);
861
 			);

+ 17
- 0
playground/src/screens/WelcomeScreen.js View File

23
     this.onClickShowModal = this.onClickShowModal.bind(this);
23
     this.onClickShowModal = this.onClickShowModal.bind(this);
24
     this.onClickLifecycleScreen = this.onClickLifecycleScreen.bind(this);
24
     this.onClickLifecycleScreen = this.onClickLifecycleScreen.bind(this);
25
     this.onClickPushOptionsScreen = this.onClickPushOptionsScreen.bind(this);
25
     this.onClickPushOptionsScreen = this.onClickPushOptionsScreen.bind(this);
26
+    this.onClickPushNativeComponent = this.onClickPushNativeComponent.bind(this);
26
     this.onClickPushOrientationMenuScreen = this.onClickPushOrientationMenuScreen.bind(this);
27
     this.onClickPushOrientationMenuScreen = this.onClickPushOrientationMenuScreen.bind(this);
27
     this.onClickBackHandler = this.onClickBackHandler.bind(this);
28
     this.onClickBackHandler = this.onClickBackHandler.bind(this);
28
     this.onClickPushTopTabsScreen = this.onClickPushTopTabsScreen.bind(this);
29
     this.onClickPushTopTabsScreen = this.onClickPushTopTabsScreen.bind(this);
40
         <Button title='Static Lifecycle Events' testID={testIDs.PUSH_STATIC_LIFECYCLE_BUTTON} onPress={this.onClickShowStaticLifecycleOverlay} />
41
         <Button title='Static Lifecycle Events' testID={testIDs.PUSH_STATIC_LIFECYCLE_BUTTON} onPress={this.onClickShowStaticLifecycleOverlay} />
41
         <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
42
         <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
42
         <Button title='Push Options Screen' testID={testIDs.PUSH_OPTIONS_BUTTON} onPress={this.onClickPushOptionsScreen} />
43
         <Button title='Push Options Screen' testID={testIDs.PUSH_OPTIONS_BUTTON} onPress={this.onClickPushOptionsScreen} />
44
+        <Button title='Push Native Component' testID={testIDs.PUSH_NATIVE_COMPONENT_BUTTON} onPress={this.onClickPushNativeComponent} />
43
         {Platform.OS === 'android' && <Button title='Push Top Tabs screen' testID={testIDs.PUSH_TOP_TABS_BUTTON} onPress={this.onClickPushTopTabsScreen} />}
45
         {Platform.OS === 'android' && <Button title='Push Top Tabs screen' testID={testIDs.PUSH_TOP_TABS_BUTTON} onPress={this.onClickPushTopTabsScreen} />}
44
         {Platform.OS === 'android' && <Button title='Back Handler' testID={testIDs.BACK_HANDLER_BUTTON} onPress={this.onClickBackHandler} />}
46
         {Platform.OS === 'android' && <Button title='Back Handler' testID={testIDs.BACK_HANDLER_BUTTON} onPress={this.onClickBackHandler} />}
45
         <Button title='Show Modal' testID={testIDs.SHOW_MODAL_BUTTON} onPress={this.onClickShowModal} />
47
         <Button title='Show Modal' testID={testIDs.SHOW_MODAL_BUTTON} onPress={this.onClickShowModal} />
231
     });
233
     });
232
   }
234
   }
233
 
235
 
236
+  async onClickPushNativeComponent() {
237
+    await Navigation.push(this.props.componentId, {
238
+      nativeComponent: {
239
+        name: 'RNNCustomViewController',
240
+        options: {
241
+          topBar: {
242
+            title: 'pushed',
243
+            visible: true,
244
+            testID: testIDs.TOP_BAR_ELEMENT
245
+          }
246
+        }
247
+      }
248
+    });
249
+  }
250
+
234
   onClickLifecycleScreen() {
251
   onClickLifecycleScreen() {
235
     Navigation.push(this.props.componentId, {
252
     Navigation.push(this.props.componentId, {
236
       component: {
253
       component: {

+ 1
- 0
playground/src/testIDs.js View File

53
   OK_BUTTON: `OK_BUTTON`,
53
   OK_BUTTON: `OK_BUTTON`,
54
   MODAL_WITH_STACK_BUTTON: `MODAL_WITH_STACK_BUTTON`,
54
   MODAL_WITH_STACK_BUTTON: `MODAL_WITH_STACK_BUTTON`,
55
   CUSTOM_TRANSITION_BUTTON: `CUSTOM_TRANSITION_BUTTON`,
55
   CUSTOM_TRANSITION_BUTTON: `CUSTOM_TRANSITION_BUTTON`,
56
+  PUSH_NATIVE_COMPONENT_BUTTON: `PUSH_NATIVE_COMPONENT_BUTTON`,
56
 
57
 
57
   // Elements
58
   // Elements
58
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,
59
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,