Reputation: 7145
I want to create a simple UIView subclass and then make it available as a React Native JavaScript component via bridging to React Native. I have followed these directions and thumbed through lots of the react source code: https://facebook.github.io/react-native/docs/native-components-ios.html
Unfortunately, I don't know where my React Native component is failing. This is my Obj-C manager class:
// header
#import "RCTViewManager.h"
#import "ColorPicker.h"
@interface ColorPickerManager : RCTViewManager
@end
// implementation
#import "ColorPickerManager.h"
@interface ColorPickerManager()
@property (nonatomic) ColorPicker * colorPicker;
@end
@implementation ColorPickerManager
RCT_EXPORT_MODULE()
- (instancetype)init {
self = [super init];
if ( self ) {
NSLog(@"color picker manager init");
self.colorPicker = [[ColorPicker alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
}
return self;
}
- (UIView *)view {
NSLog(@"color picker manager -view method");
return self.colorPicker;
}
@end
Here is my simple UIView subclass that I vend via the above -view
method:
// header
#import <UIKit/UIKit.h>
@interface ColorPicker : UIView
@end
// implementation
#import "ColorPicker.h"
@interface ColorPicker()
@property (nonatomic) NSArray * colors;
@end
@implementation ColorPicker
- (instancetype)init {
NSLog(@"init");
self = [super init];
if ( self ) {
[self setUp];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
NSLog(@"init with frame: %@", NSStringFromCGRect(frame));
self = [super initWithFrame:frame];
if ( self ) {
[self setUp];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
NSLog(@"init with coder: %@", aDecoder);
self = [super initWithCoder:aDecoder];
if ( self ) {
[self setUp];
}
return self;
}
- (void)setUp {
self.colors = @[[UIColor redColor], [UIColor greenColor], [UIColor blueColor]];
self.backgroundColor = self.colors[0];
}
- (void)layoutSubviews {
NSLog(@"layout subviews");
}
@end
Finally, here's my react component being bridged over to JavaScript:
var { requireNativeComponent } = require('react-native');
var ColorPicker = requireNativeComponent('ColorPicker', null);
module.exports = ColorPicker;
debugger;
And it's declaration and render to the screen:
'use strict';
var React = require('react-native');
var ColorPicker = require('./BridgedComponents/ColorPicker.js');
var {
StyleSheet
} = React;
var iOS = React.createClass({
render: function() {
debugger;
return (
<ColorPicker style={styles.container} />
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
AppRegistry.registerComponent('iOS', () => iOS);
This results in nothing rendering to the screen when I expect to see a 100x100 red square. What I have tried:
UIView
will render exactly what I expect if I remove all React Native code from the project and by putting this view as a subview of a different rootViewController
.ColorPicker
in my main .js file is not undefined
at the time its rendered to screen and when its created via debugger
. height: 100, width: 100
to the rendered ColorPicker
but it still doesn't show a red squAREQuestions for RN Gurus - What else can I do to verify that my view is correctly bridged? - Is there anything I should look for in the Chrome Debugger when inspecting these instances to verify that the view was set up correctly? - I've tried following some of the source code in the repo but I'm still new to React and I'm not 100% how its all working. - When I create a bridged component am I expected to set the appearance and layout in the Obj-C/Swift class or is it better to do that in JavaScript with CSS. Seems to me the former would be expected.
Any help/advice will be greatly appreciated.
Upvotes: 3
Views: 1963
Reputation: 6716
You don't see anything but your ColorPicker
view is added.
The problem is ReactNative is managing its backgroundColor
property itself and overrides your initial choice.
You can add the following method in your ColorPicker.m
and put a breakpoint to see when it happens:
- (void)setBackgroundColor:(UIColor *)backgroundColor {
NSLog(@"setBackgroundColor %@", backgroundColor);
[super setBackgroundColor:backgroundColor];
}
You should let React Native handle the size and appearance of your bridged component. But it's totally find to have custom subviews that are entirely controlled from the native side.
Also your ColorPickerManager
should return a new instance of the view you're bridging whenever it calls the view
method.
i.e. you should use this:
@implementation ColorPickerManager
RCT_EXPORT_MODULE()
- (instancetype)init {
self = [super init];
if ( self ) {
NSLog(@"color picker manager init");
}
return self;
}
- (UIView *)view {
NSLog(@"color picker manager -view method");
return [[ColorPicker alloc] init];
}
@end
Otherwise you won't be able to display 2 (or more) instances of your ColorPicker component.
Upvotes: 1