anbu selvan
anbu selvan

Reputation: 745

Run React Native inside View Controller

I am building a test app in react native where the main view is React Native and the toolbar is Native Part(Android/iOS).Like this ct image so in Android i used Fragment to run react native and attached the fragment to the main app.I used this answer.But now i need to do the same thing for iOS any useful links or blogs will be helpful.

[Edit]: After @Murilo Paixão suggestion i changed the AppDelegate to below :-

let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "swiftdemoapp", initialProperties: nil, launchOptions: launchOptions)
let rootViewController = TwtViewController()
rootViewController.view = rootView

where TwtViewController inherits from UiViewController and has a stroyboard connected to it.

enter image description here

So now when i run my app the whole screen is occupied by react native how to adjust the size or do i need child view controller to be placed so that i can see the native label.

Upvotes: 1

Views: 2524

Answers (1)

Murilo Paixão
Murilo Paixão

Reputation: 646

Assume you have the following component:

import React from 'react';
import { AppRegistry, View, Text } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#FFFFFF',
  },
});

class SimpleTextComponent extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>{this.props.text}</Text>
      </View>
    );
  }
}

// module name
AppRegistry.registerComponent('SimpleTextComponent', () => SimpleTextComponent);

And now you want to load it inside an ordinary UIViewController from iOS. You just need to do as follow:

// Run this before presenting the view controller inside your native iOS app.

// In this case, index.bundle matches the index.js file that contains your component code
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];

// Provide the same module name used on AppRegistry
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                    moduleName:@"SimpleTextComponent"
                                             initialProperties:@{@"text": "React Native Content"}
                                                 launchOptions:nil];

UIViewController *viewController = [UIViewController new];
viewController.view = rootView;
[self presentViewController:viewController animated:YES completion:nil];

You can see more on react native page.

Edit 1:

So, as I see you still have problems mixing react-native and native iOS code, I will go through a more complete example, I really hope this helps :)

Let's build this app in three simple steps:

enter image description here

This orange view was added with Xcode's interface builder and the blue one came from a react-native component. Also, note the navigation bar, it's a native UINavigationController!

Step 1

Create a view controller with an associated xib file and add a label.

Go to New File and select Cocoa Touch Class: enter image description here

Then, on subclass select UIViewController and mark Also create XIB file:

Note: I'm sticking with Objective-C because it's easier to deal with react-native, but you can do it with Swift too :)

enter image description here

Now, you should get an empty template for a view controller with a XIB file.

Step 2

Add a label to your view on interface builder, it can be something as follow:

enter image description here

Then, modify your AppDelegate.m and embed your new view controller inside a UINavigationController and set it as your root view controller:

#import "AppDelegate.h"
#import "NativeLabelViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NativeLabelViewController *rootViewController = [[NativeLabelViewController alloc] initWithNibName:@"NativeLabelViewController"
                                                                                              bundle:[NSBundle mainBundle]];
  UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: rootViewController];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  self.window.rootViewController = navigationController;
  [self.window makeKeyAndVisible];

  return YES;
}

@end

Step 3

Now let's embed a react component in our view \o/.

First, create a RCTRootView and populate it with some js code, like this:

Note: I just used the same component from the previous example.

// index here matches the index.js file on your project's root.
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
UIView *reactView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                moduleName:@"SimpleTextComponent"
                                         initialProperties:@{@"text": @"I came from React Native \\o/"}
                                             launchOptions:nil];

Now, add some constraints for it. I chose to match the superview's bottom, leading and trailing, and match the vertical center for top constraint:

// Setup react view constraints
[self.view addSubview:reactView];
[reactView setTranslatesAutoresizingMaskIntoConstraints:NO];

NSLayoutConstraint *leadingConstraint = [reactView.leadingAnchor constraintEqualToAnchor:[self.view leadingAnchor]];
NSLayoutConstraint *bottomConstraint = [reactView.bottomAnchor constraintEqualToAnchor:[self.view bottomAnchor]];
NSLayoutConstraint *trailingConstraint = [reactView.trailingAnchor constraintEqualToAnchor:[self.view trailingAnchor]];
NSLayoutConstraint *topConstraint = [reactView.topAnchor constraintEqualToAnchor:[self.view centerYAnchor]];

[self.view addConstraints:@[leadingConstraint, bottomConstraint, trailingConstraint, topConstraint]];
[self.view setNeedsUpdateConstraints];

The final file should look like this:

#import "NativeLabelViewController.h"
#import <React/RCTRootView.h>
#import <React/RCTBundleURLProvider.h>

@interface NativeLabelViewController ()

@end

@implementation NativeLabelViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  self.title = @"Mixed react-native and iOS views";
  [self setupReactView];
}

- (void)setupReactView {
  NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  UIView *reactView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                  moduleName:@"SimpleTextComponent"
                                           initialProperties:@{@"text": @"I came from React Native \\o/"}
                                               launchOptions:nil];

  // Setup react view constraints
  [self.view addSubview:reactView];
  [reactView setTranslatesAutoresizingMaskIntoConstraints:NO];

  NSLayoutConstraint *leadingConstraint = [reactView.leadingAnchor constraintEqualToAnchor:[self.view leadingAnchor]];
  NSLayoutConstraint *bottomConstraint = [reactView.bottomAnchor constraintEqualToAnchor:[self.view bottomAnchor]];
  NSLayoutConstraint *trailingConstraint = [reactView.trailingAnchor constraintEqualToAnchor:[self.view trailingAnchor]];
  NSLayoutConstraint *topConstraint = [reactView.topAnchor constraintEqualToAnchor:[self.view centerYAnchor]];

  [self.view addConstraints:@[leadingConstraint, bottomConstraint, trailingConstraint, topConstraint]];
  [self.view setNeedsUpdateConstraints];
}

@end

That's it. Run it and the result should look like the following:

enter image description here

Upvotes: 6

Related Questions