React Native Learning - Encapsulating native UI components (iOS)

Keywords: React Attribute github Javascript



Native development, developed to today has been very mature and perfect, there are tens of thousands of components, greatly improving the development efficiency. React Native, on Facebook's React.js conf 2015, argues that for more than a year now, the number of components is certainly not comparable to the original number.
Therefore, in developing App using React Native, we may need to call native view components or third-party components that RN does not implement. Even, we can construct a local module as a React Native component for others to use.

This demo is based on SDCycle ScrollView, or banner, because there are no good examples, so the SDCycle ScrollView used in the project is encapsulated and directly invoked to js.

SDCycleScrollView is a github open source, infinite loop automatic picture rotator.
The address is: https://github.com/gsdios/SDCycleScrollView
SDWeb Image is used in the project. If SDWeb Image is used in the project, it is recommended that the SDCycleScrollView related code be pulled directly into the project.

I. Further encapsulation of native views

Referring to other people's encapsulation of native views, most of them will create a new view, inherit (or sub-view contains) native views, which may contain calls to events (here simple demo, not used).
# import "UIView+React.h" to extend the native view (here is an important attribute reactTag, which will be used later as a differentiated purpose).

TestScrollView.h

#import "SDCycleScrollView.h"


#import "RCTComponent.h"
#import "UIView+React.h"


@interface TestScrollView : SDCycleScrollView


@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;


@end

The block attribute of RCTBubbling EventBlock or RCTBubbling EventBlock type is declared in the encapsulated UIView before it can be exported as an event. (New way to export events, which will be used later)
Note: Declare that the name of the block attribute should begin with on (unsure why, only on can succeed without other configuration)

TestScrollView.m

#import "TestScrollView.h"


@implementation TestScrollView


/**
 *  Many third-party components that encapsulate native components are written in this way, and they have not been studied thoroughly here, so they are not implemented according to the rules.
- (instancetype)initWithBridge:(RCTBridge *)bridge {
    if ((self = [super initWithFrame:CGRectZero])) {
        _eventDispatcher = bridge.eventDispatcher;
        _bridge = bridge;
        ......
    }
    return self;
}
 */
@end

2. Create RCTViewManager subclass to create and manage native views

Native views need to be created and managed by a subclass of RCTViewManager.
These managers are somewhat like "view controllers" in functionality, but they are essentially singletons - React Native only creates one instance for each manager.
They create native views and provide them to RCTUI Manager, which in turn delegates them to set and update the properties of views when needed. RCTViewManager also proxies all delegates to the view and sends back the corresponding events to JavaScript.

The steps to provide a native view are as follows:

  • First, create a subclass named "View Name + Manager" in the naming specification. View names can be prefixed with their own prefix. It's best to avoid using RCT prefix here unless you want to give the official pull request.
  • Add RCT_EXPORT_MODULE() tag macros -- exposing module interfaces to JavaScript
  • Implementing the - (UIView *)view method -- Creating and returning component views
  • Encapsulating attributes and passing events

The complete code is posted below, and then the attributes and events are explained further.

TestScrollViewManager.h

#import "RCTViewManager.h"


@interface TestScrollViewManager : RCTViewManager


@end

TestScrollViewManager.m

#import "TestScrollViewManager.h"
#import "TestScrollView.h"      //Header files for third-party components


#import "RCTBridge.h"           //Header file for communication
#import "RCTEventDispatcher.h"  //Event dispatch, no import will cause Xcode warning


@interface TestScrollViewManager() <SDCycleScrollViewDelegate>


@end


@implementation TestScrollViewManager


//  Markup macros (necessary)
RCT_EXPORT_MODULE()


//  Event export, onClickBanner corresponds to extended attributes in view
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)


//  Mapping and exporting attributes through macro RCT_EXPORT_VIEW_PROPERTY
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);


RCT_EXPORT_VIEW_PROPERTY(imageURLStringsGroup, NSArray);


RCT_EXPORT_VIEW_PROPERTY(autoScroll, BOOL);


- (UIView *)view
{
    //  The specific size and location of the actual components are controlled by js
    TestScrollView *testScrollView = [TestScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
    //  Initialization points delegate to self
    testScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleClassic;
    testScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
    return testScrollView;
}


/**
 *  When event exporting uses sendInputEventWithName, it uses
- (NSArray *) customDirectEventTypes {
    return @[@"onClickBanner"];
}
 */


#pragma mark SDCycleScrollViewDelegate
/**
 *  banner click
 */
- (void)cycleScrollView:(TestScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
//    This is also the way to export events, but it seems like the old way, there will be warnings.
//    [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
//                                                   body:@{@"target": cycleScrollView.reactTag,
//                                                          @"value": [NSNumber numberWithInteger:index+1]
//                                                        }];


    if (!cycleScrollView.onClickBanner) {
        return;
    }


    NSLog(@"oc did click %li", [cycleScrollView.reactTag integerValue]);


    //  Export event
    cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
                                    @"value": [NSNumber numberWithInteger:index+1]});
}


// Export enumeration constants to define styles for js
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}


//  Because this class inherits RCTViewManager and implements RCTBridgeModule, all the features of native modules can be used.
//  This method has not been used for the time being.
RCT_EXPORT_METHOD(testResetTime:(RCTResponseSenderBlock)callback) {
    callback(@[@(234)]);
}


@end

attribute

RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);

The mapping and exporting of attributes are completed by macro RCT_EXPORT_VIEW_PROPERTY.
CGFloat is the OC data type of autoScrollTime Interval, and converted to js corresponds to number.

React Native uses RCTConvert to perform type conversion between JavaScript and native code.
The default conversion types (parts) supported are as follows:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) contains any type in this list
  • map (NSDictionary) contains keys of string type and values of any type in this list

If the conversion cannot be completed, a "red screen" error message will be generated, so that you can immediately know that there is a problem in the code. If all goes well, the macro above already contains all the implementations of the exported properties.

ps: More complex type conversion involves MKCoordination Region type, which is not applied in this paper. Reference can be made to official document examples.

Event

js and native need to interact with each other. for example, when native agent or click event is implemented and js needs to get such event in real time, it needs to interact with events.
There are two ways to implement events:

  1. Implementation by sendInputEventWithName
    1) Implement customDirectEventTypes and return a custom array of event names (on starts only valid)

    - (NSArray *) customDirectEventTypes {
     return @[@"onClickBanner"];
    }

    2) sendInputEventWithName implements event calls (reactTag for instance discrimination)

    [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
                                                   body:@{@"target": cycleScrollView.reactTag,
                                                          @"value": [NSNumber numberWithInteger:index+1]
                                                         }];
  2. Implementation by RCT Bubbling Event Block
    1) Add the block attribute of RCTBubbling EventBlock to the encapsulated View (on is valid at the beginning)

    @property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;

    2) Mapping and exporting Block attributes in Manager class by macro RCT_EXPORT_VIEW_PROPERTY

    RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)

    3) Implementing event calls (reactTag for instance discrimination)

    cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
                                     @"value": [NSNumber numberWithInteger:index+1]});

By encapsulating the events in the above two ways, you can directly use the same name function call in js (shown later).
However, there are many things about events that are not fully understood. I hope that God will guide us, such as why we can only define the beginning of on, how to customize it, how to call back the event data source, and so on.

style

Because all our views are subclasses of UIView, most of the style attributes should take effect directly. Some attribute definitions, which require enumeration, can be implemented by means of constants passed in natively, as follows:

// Export enumeration constants to define styles for js
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}

Called in js as follows:

//  First, we get the constants.
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;


//  call

ps: Some components will want to use their own defined default styles, such as UIDatePicker, which wants their size to be fixed. For example, size is the default size. This example can be used for reference. Official documents Style module.

3. Calling in JS

There are two ways to call in js, one is to call directly as an extended React component, the other is to encapsulate a new component, and then make a call.
In the second way, the official recommendation makes the logic clear.

1. Pour in the native component first, create a new TestScrollView.js file, import TestScrollView in it, declare the attribute type, etc. Specific codes and explanations are as follows:

TestScrollView.js

// TestScrollView.js


import React, { Component, PropTypes } from 'react';
import { requireNativeComponent } from 'react-native';


// RequireNative Component automatically provides this component to "RCTScrollView"
var RCTScrollView = requireNativeComponent('TestScrollView', TestScrollView);


export default class TestScrollView extends Component {


  render() {
    return <RCTScrollView {...this.props} />;
  }


}


TestScrollView.propTypes = {
    /**
    * Attribute type, in fact, can not write, js will automatically convert the type
    */
    autoScrollTimeInterval: PropTypes.number,
    imageURLStringsGroup: PropTypes.array,
    autoScroll: PropTypes.bool,


    onClickBanner: PropTypes.func
};


module.exports = TestScrollView;

2. Call in index.ios.js

index.ios.js

var TestScrollView = require('./TestScrollView');


// RequireNative Component automatically provides this component to "TestScrollView"
// If you do not create a new TestScrollView.js encapsulation declaration for native components, you can import it directly with this sentence
// var TestScrollView = requireNativeComponent('TestScrollView', null);


// Import constants
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;


var bannerImgs = [
  'http://upload-images.jianshu.io/upload_images/2321678-ba5bf97ec3462662.png?imageMogr2/auto-orient/strip%7CimageView2/2',
  'http://upload-images.jianshu.io/upload_images/1487291-2aec9e634117c24b.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/480/q/100',
  'http://f.hiphotos.baidu.com/zhidao/pic/item/e7cd7b899e510fb37a4f2df3db33c895d1430c7b.jpg'
];


class NativeUIModule extends Component {


  constructor(props){
    super(props);
    this.state={
        bannerNum:0
    }
  }


  render() {


    return (
      <ScrollView style = {{marginTop:64}}>
      <View>
        <TestScrollView style={styles.container} 
          autoScrollTimeInterval = {2}
          imageURLStringsGroup = {bannerImgs}
          pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
          onClickBanner={(e) => {
            console.log('test' + e.nativeEvent.value);
            this.setState({bannerNum:e.nativeEvent.value});
          }}
        />
        <Text style={{fontSize: 15, margin: 10, textAlign:'center'}}>
          //Click banner - > {this. state. bannerNum}
        Text>
      View>
      ScrollView>
    );
  }
}


//  The specific size and location of the actual components are controlled by js
const styles = StyleSheet.create({
  container:{
    padding:30,
    borderColor:'#e7e7e7',
    marginTop:10,
    height:200,
  },
});


AppRegistry.registerComponent('NativeTest2', () => NativeUIModule);

If you use the first method, you can use the following statement to refer to a component:

var TestScrollView = requireNativeComponent('TestScrollView', null);

Then there will be such problems:
It's convenient and simple, but it doesn't explain the use of this component very well - if the user wants to know what attributes of our component can be used and what values can be obtained, he has to flip all the way to Objective-C code. To solve this problem, we can create an encapsulated component and illustrate its interface through PropTypes.

Note: We now change the second parameter of requireNativeComponent from null to TestScrollView for encapsulation. This allows React Native's underlying framework to check whether the attributes of native and wrapper classes are consistent, reducing the possibility of problems.

For the invocation of attributes and events, the following direct invocation is made:

2}
          imageURLStringsGroup = {bannerImgs}
          pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
          onClickBanner={(e) => {
            console.log('test' + e.nativeEvent.value);
            this.setState({bannerNum:e.nativeEvent.value});
          }}
/>

With regard to events, it should be noted that the default transfer of event events is the dictionary data type, json. Calling in js requires the use of e.nativeEvent to extract the dictionary and the value in the specific call. (There is no thorough study here, and guidance is needed.)

React Native and Primitive Mixed code calls each other. The classic items are as follows:

Link: https://pan.baidu.com/s/1kVwRnYB password: vuwz

Native development, developed to today has been very mature and perfect, there are tens of thousands of components, greatly improving the development efficiency. React Native, on Facebook's React.js conf 2015, argues that for more than a year now, the number of components is certainly not comparable to the original number.
Therefore, in developing App using React Native, we may need to call native view components or third-party components that RN does not implement. Even, we can construct a local module as a React Native component for others to use.

This demo is based on SDCycle ScrollView, or banner, because there are no good examples, so the SDCycle ScrollView used in the project is encapsulated and directly invoked to js.

SDCycleScrollView is a github open source, infinite loop automatic picture rotator.
The address is: https://github.com/gsdios/SDCycleScrollView
SDWeb Image is used in the project. If SDWeb Image is used in the project, it is recommended that the SDCycleScrollView related code be pulled directly into the project.

I. Further encapsulation of native views

Referring to other people's encapsulation of native views, most of them will create a new view, inherit (or sub-view contains) native views, which may contain calls to events (here simple demo, not used).
# import "UIView+React.h" to extend the native view (here is an important attribute reactTag, which will be used later as a differentiated purpose).

TestScrollView.h

#import "SDCycleScrollView.h"


#import "RCTComponent.h"
#import "UIView+React.h"


@interface TestScrollView : SDCycleScrollView


@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;


@end

The block attribute of RCTBubbling EventBlock or RCTBubbling EventBlock type is declared in the encapsulated UIView before it can be exported as an event. (New way to export events, which will be used later)
Note: Declare that the name of the block attribute should begin with on (unsure why, only on can succeed without other configuration)

TestScrollView.m

#import "TestScrollView.h"


@implementation TestScrollView


/**
 *  Many third-party components that encapsulate native components are written in this way, and they have not been studied thoroughly here, so they are not implemented according to the rules.
- (instancetype)initWithBridge:(RCTBridge *)bridge {
    if ((self = [super initWithFrame:CGRectZero])) {
        _eventDispatcher = bridge.eventDispatcher;
        _bridge = bridge;
        ......
    }
    return self;
}
 */
@end

2. Create RCTViewManager subclass to create and manage native views

Native views need to be created and managed by a subclass of RCTViewManager.
These managers are somewhat like "view controllers" in functionality, but they are essentially singletons - React Native only creates one instance for each manager.
They create native views and provide them to RCTUI Manager, which in turn delegates them to set and update the properties of views when needed. RCTViewManager also proxies all delegates to the view and sends back the corresponding events to JavaScript.

The steps to provide a native view are as follows:

  • First, create a subclass named "View Name + Manager" in the naming specification. View names can be prefixed with their own prefix. It's best to avoid using RCT prefix here unless you want to give the official pull request.
  • Add RCT_EXPORT_MODULE() tag macros -- exposing module interfaces to JavaScript
  • Implementing the - (UIView *)view method -- Creating and returning component views
  • Encapsulating attributes and passing events

The complete code is posted below, and then the attributes and events are explained further.

TestScrollViewManager.h

#import "RCTViewManager.h"


@interface TestScrollViewManager : RCTViewManager


@end

TestScrollViewManager.m

#import "TestScrollViewManager.h"
#import "TestScrollView.h"      //Header files for third-party components


#import "RCTBridge.h"           //Header file for communication
#import "RCTEventDispatcher.h"  //Event dispatch, no import will cause Xcode warning


@interface TestScrollViewManager() <SDCycleScrollViewDelegate>


@end


@implementation TestScrollViewManager


//  Markup macros (necessary)
RCT_EXPORT_MODULE()


//  Event export, onClickBanner corresponds to extended attributes in view
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)


//  Mapping and exporting attributes through macro RCT_EXPORT_VIEW_PROPERTY
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);


RCT_EXPORT_VIEW_PROPERTY(imageURLStringsGroup, NSArray);


RCT_EXPORT_VIEW_PROPERTY(autoScroll, BOOL);


- (UIView *)view
{
    //  The specific size and location of the actual components are controlled by js
    TestScrollView *testScrollView = [TestScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
    //  Initialization points delegate to self
    testScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleClassic;
    testScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
    return testScrollView;
}


/**
 *  When event exporting uses sendInputEventWithName, it uses
- (NSArray *) customDirectEventTypes {
    return @[@"onClickBanner"];
}
 */


#pragma mark SDCycleScrollViewDelegate
/**
 *  banner click
 */
- (void)cycleScrollView:(TestScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
//    This is also the way to export events, but it seems like the old way, there will be warnings.
//    [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
//                                                   body:@{@"target": cycleScrollView.reactTag,
//                                                          @"value": [NSNumber numberWithInteger:index+1]
//                                                        }];


    if (!cycleScrollView.onClickBanner) {
        return;
    }


    NSLog(@"oc did click %li", [cycleScrollView.reactTag integerValue]);


    //  Export event
    cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
                                    @"value": [NSNumber numberWithInteger:index+1]});
}


// Export enumeration constants to define styles for js
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}


//  Because this class inherits RCTViewManager and implements RCTBridgeModule, all the features of native modules can be used.
//  This method has not been used for the time being.
RCT_EXPORT_METHOD(testResetTime:(RCTResponseSenderBlock)callback) {
    callback(@[@(234)]);
}


@end

attribute

RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);

The mapping and exporting of attributes are completed by macro RCT_EXPORT_VIEW_PROPERTY.
CGFloat is the OC data type of autoScrollTime Interval, and converted to js corresponds to number.

React Native uses RCTConvert to perform type conversion between JavaScript and native code.
The default conversion types (parts) supported are as follows:

  • string (NSString)
  • number (NSInteger, float, double, CGFloat, NSNumber)
  • boolean (BOOL, NSNumber)
  • array (NSArray) contains any type in this list
  • map (NSDictionary) contains keys of string type and values of any type in this list

If the conversion cannot be completed, a "red screen" error message will be generated, so that you can immediately know that there is a problem in the code. If all goes well, the macro above already contains all the implementations of the exported properties.

ps: More complex type conversion involves MKCoordination Region type, which is not applied in this paper. Reference can be made to official document examples.

Event

js and native need to interact with each other. for example, when native agent or click event is implemented and js needs to get such event in real time, it needs to interact with events.
There are two ways to implement events:

  1. Implementation by sendInputEventWithName
    1) Implement customDirectEventTypes and return a custom array of event names (on starts only valid)

    - (NSArray *) customDirectEventTypes {
     return @[@"onClickBanner"];
    }

    2) sendInputEventWithName implements event calls (reactTag for instance discrimination)

    [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
                                                   body:@{@"target": cycleScrollView.reactTag,
                                                          @"value": [NSNumber numberWithInteger:index+1]
                                                         }];
  2. Implementation by RCT Bubbling Event Block
    1) Add the block attribute of RCTBubbling EventBlock to the encapsulated View (on is valid at the beginning)

    @property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;

    2) Mapping and exporting Block attributes in Manager class by macro RCT_EXPORT_VIEW_PROPERTY

    RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)

    3) Implementing event calls (reactTag for instance discrimination)

    cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
                                     @"value": [NSNumber numberWithInteger:index+1]});

By encapsulating the events in the above two ways, you can directly use the same name function call in js (shown later).
However, there are many things about events that are not fully understood. I hope that God will guide us, such as why we can only define the beginning of on, how to customize it, how to call back the event data source, and so on.

style

Because all our views are subclasses of UIView, most of the style attributes should take effect directly. Some attribute definitions, which require enumeration, can be implemented by means of constants passed in natively, as follows:

// Export enumeration constants to define styles for js
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}

Called in js as follows:

//  First, we get the constants.
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;


//  call

ps: Some components will want to use their own defined default styles, such as UIDatePicker, which wants their size to be fixed. For example, size is the default size. This example can be used for reference. Official documents Style module.

3. Calling in JS

There are two ways to call in js, one is to call directly as an extended React component, the other is to encapsulate a new component, and then make a call.
In the second way, the official recommendation makes the logic clear.

1. Pour in the native component first, create a new TestScrollView.js file, import TestScrollView in it, declare the attribute type, etc. Specific codes and explanations are as follows:

TestScrollView.js

// TestScrollView.js


import React, { Component, PropTypes } from 'react';
import { requireNativeComponent } from 'react-native';


// RequireNative Component automatically provides this component to "RCTScrollView"
var RCTScrollView = requireNativeComponent('TestScrollView', TestScrollView);


export default class TestScrollView extends Component {


  render() {
    return <RCTScrollView {...this.props} />;
  }


}


TestScrollView.propTypes = {
    /**
    * Attribute type, in fact, can not write, js will automatically convert the type
    */
    autoScrollTimeInterval: PropTypes.number,
    imageURLStringsGroup: PropTypes.array,
    autoScroll: PropTypes.bool,


    onClickBanner: PropTypes.func
};


module.exports = TestScrollView;

2. Call in index.ios.js

index.ios.js

var TestScrollView = require('./TestScrollView');


// RequireNative Component automatically provides this component to "TestScrollView"
// If you do not create a new TestScrollView.js encapsulation declaration for native components, you can import it directly with this sentence
// var TestScrollView = requireNativeComponent('TestScrollView', null);


// Import constants
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;


var bannerImgs = [
  'http://upload-images.jianshu.io/upload_images/2321678-ba5bf97ec3462662.png?imageMogr2/auto-orient/strip%7CimageView2/2',
  'http://upload-images.jianshu.io/upload_images/1487291-2aec9e634117c24b.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/480/q/100',
  'http://f.hiphotos.baidu.com/zhidao/pic/item/e7cd7b899e510fb37a4f2df3db33c895d1430c7b.jpg'
];


class NativeUIModule extends Component {


  constructor(props){
    super(props);
    this.state={
        bannerNum:0
    }
  }


  render() {


    return (
      <ScrollView style = {{marginTop:64}}>
      <View>
        <TestScrollView style={styles.container} 
          autoScrollTimeInterval = {2}
          imageURLStringsGroup = {bannerImgs}
          pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
          onClickBanner={(e) => {
            console.log('test' + e.nativeEvent.value);
            this.setState({bannerNum:e.nativeEvent.value});
          }}
        />
        <Text style={{fontSize: 15, margin: 10, textAlign:'center'}}>
          //Click banner - > {this. state. bannerNum}
        Text>
      View>
      ScrollView>
    );
  }
}


//  The specific size and location of the actual components are controlled by js
const styles = StyleSheet.create({
  container:{
    padding:30,
    borderColor:'#e7e7e7',
    marginTop:10,
    height:200,
  },
});


AppRegistry.registerComponent('NativeTest2', () => NativeUIModule);

If you use the first method, you can use the following statement to refer to a component:

var TestScrollView = requireNativeComponent('TestScrollView', null);

Then there will be such problems:
It's convenient and simple, but it doesn't explain the use of this component very well - if the user wants to know what attributes of our component can be used and what values can be obtained, he has to flip all the way to Objective-C code. To solve this problem, we can create an encapsulated component and illustrate its interface through PropTypes.

Note: We now change the second parameter of requireNativeComponent from null to TestScrollView for encapsulation. This allows React Native's underlying framework to check whether the attributes of native and wrapper classes are consistent, reducing the possibility of problems.

For the invocation of attributes and events, the following direct invocation is made:

2}
          imageURLStringsGroup = {bannerImgs}
          pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
          onClickBanner={(e) => {
            console.log('test' + e.nativeEvent.value);
            this.setState({bannerNum:e.nativeEvent.value});
          }}
/>

With regard to events, it should be noted that the default transfer of event events is the dictionary data type, json. Calling in js requires the use of e.nativeEvent to extract the dictionary and the value in the specific call. (There is no thorough study here, and guidance is needed.)

React Native and Primitive Mixed code calls each other. The classic items are as follows:

Link: https://pan.baidu.com/s/1kVwRnYB password: vuwz


Posted by NoDoze on Thu, 03 Jan 2019 09:51:11 -0800