React Native Life Cycle and Communication

Life Cycle:

Communication:

Ref:React Native 中组件的生命周期

Ref:React Native通信机制详解

Ref:Communication between native and React Native

Ref:http://www.cnblogs.com/cwgk/tag/ReactNative/

Ref:custom-ios-views-with-react-native

#import "RCTViewManager.h"
@interface MyCustomViewManager : RCTViewManager

@end
MyCustomViewManager.h
#import "MyCustomViewManager.h"
#import "MyCustomView.h"

@implementation MyCustomViewManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
  MyCustomView * theView;
  theView = [[MyCustomView alloc] initWithFrame:CGRectMake(0,0,10,10)];
  return theView;
}

RCT_EXPORT_VIEW_PROPERTY(srcImagePath, NSString);
RCT_EXPORT_VIEW_PROPERTY(cropImageWidth, NSInteger);
RCT_EXPORT_VIEW_PROPERTY(cropImageHeight, NSInteger);
RCT_EXPORT_VIEW_PROPERTY(textHeight, NSInteger);
RCT_EXPORT_VIEW_PROPERTY(textFontSize, NSInteger);
RCT_EXPORT_VIEW_PROPERTY(textFontFamily, NSString);
RCT_EXPORT_VIEW_PROPERTY(textContent, NSString);
@end
MyCustomViewManager.m
#import <UIKit/UIKit.h>

@interface MyCustomView : UIView
@property (nonatomic) NSString* srcImagePath;
@property (nonatomic) NSInteger cropImageWidth;
@property (nonatomic) NSInteger cropImageHeight;
@property (nonatomic) NSInteger textHeight;
@property (nonatomic) NSInteger textFontSize;
@property (nonatomic) NSString* textFontFamily;
@property (nonatomic) NSString* textContent;
@end
MyCustomView.h
#import "MyCustomView.h"

@implementation MyCustomView
{

}

- (void)setTextHeight:(NSInteger)textHeight
{
  _textHeight = textHeight;
}

- (void)setTextFontSize:(NSInteger)textFontSize
{
  _textFontSize = textFontSize;
}

-(void)setTextFontFamily:(NSString *)textFontFamily
{
  _textFontFamily = textFontFamily;
}

-(void)setTextContent:(NSString *)textContent
{
  _textContent = textContent;
}

- (void)setCropImageHeight:(NSInteger)cropImageHeight
{
  _cropImageHeight = cropImageHeight;
}

- (void)setCropImageWidth:(NSInteger)cropImageWidth
{
  _cropImageWidth = cropImageWidth;
}

- (void)setSrcImagePath:(NSString *)srcImagePath
{
  _srcImagePath = srcImagePath;
  [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
  UIImage *srcImage = [UIImage imageWithContentsOfFile:_srcImagePath];
  CGImageRef cgRef = srcImage.CGImage;
  CGFloat srcWidth = CGImageGetWidth(cgRef);
  CGFloat srcHeight = CGImageGetHeight(cgRef);
  CGImageRef imageRef = CGImageCreateWithImageInRect(cgRef,CGRectMake(
                                                                      srcWidth / 2 - _cropImageWidth / 2,
                                                                      srcHeight / 2 - _cropImageHeight / 2,
                                                                      srcWidth / 2 + _cropImageWidth / 2,
                                                                      srcHeight / 2 + _cropImageHeight / 2));
  UIImage *cropImage = [UIImage imageWithCGImage:imageRef];
  CGImageRelease(imageRef);

  UIImageView  *imageView = [[UIImageView alloc] init];
  imageView.frame = CGRectMake(0, 0, _cropImageWidth, _cropImageHeight);
  [imageView setImage:cropImage];

  [self addSubview:imageView];

  UITextView *textView = [[UITextView alloc]
                          initWithFrame:CGRectMake(0, _cropImageHeight - _textHeight, _cropImageWidth, _textHeight)];
  [textView setBackgroundColor:[UIColor blackColor]];
  [textView setTextColor:[UIColor whiteColor]];
  [textView setAlpha:0.5f];
  [textView setFont:[UIFont fontWithName:_textFontFamily size:_textFontSize]];
  [textView setText:_textContent];

  [self addSubview:textView];
  
  CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}
@end
MyCustomView.m 
/**
 * Created by NickChung on 5/17/16.
 */
import React, {Component} from 'react';
import {requireNativeComponent} from 'react-native';

var NativeMyCustomView = requireNativeComponent('MyCustomView', MyCustomView);

export default class MyCustomView extends Component {
    static propTypes = {
        srcImagePath: React.PropTypes.string,
        cropImageWidth: React.PropTypes.number,
        cropImageHeight: React.PropTypes.number,
        textFontSize: React.PropTypes.number,
        textFontHeight: React.PropTypes.number,
        textFontFamily: React.PropTypes.string,
        textContent: React.PropTypes.string
    };

    render() {
        return <NativeMyCustomView {...this.props} />;
    }
}
MyCustView.js
/**
 * Created by NickChung on 5/16/16.
 */
'use strict';

var React = require('react-native');
var {
    StyleSheet,
    Text,
    View,
    ListView,
    DeviceEventEmitter,
    NativeModules,
    Image,
    Dimensions,
    TouchableOpacity
    } = React;

const EventEmitterMixin = require('react-event-emitter-mixin');
const RealmRepo = require("./RealmRepo.js");
const History =  require("./History");
const RNFS = require('react-native-fs');
import Icon from 'react-native-vector-icons/FontAwesome';
const TimerMixin = require('react-timer-mixin');
var Modal = require('react-native-modalbox');
var Overlay = require('react-native-overlay');
import {Actions} from "react-native-router-flux";
import Detail from './Detail'
var deviceScreen = Dimensions.get('window');
var _ = require('lodash');
var Sound = require('react-native-sound');
const RNS = NativeModules.RNSound;
import MyCustView from './MyCustView'

// Create our dataSource which will be displayed in the data list
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
var beaconState = [];
var headState = {};
var openHeadState = {};
var lastBeaconId = "";
var modalState = false;
var s = null;
var orderState = null;

// The BeaconView
var BeaconView = React.createClass({
    mixins:[EventEmitterMixin],
    render: function() {
        try {
            let beacon = RealmRepo.getBeaconInfo(this.props.major, this.props.minor);
            if (beacon) {
                let content = beacon.triggercontent[0].content;
                let audio =  beacon.triggercontent[1];
                if (content) {
                    let imageUri = RNFS.DocumentDirectoryPath + content.clientpath + content.filename;
                    if(imageUri) {
                        let title = content['title_' + RealmRepo.Locale().displayLang];
                        let artist = content['artist_' + RealmRepo.Locale().displayLang];
                        let effectiveRangeIn = beacon.effectiverangein;
                        //let colorLevel = ['#FE9375', '#1DD5C0', '#00A8A7', '#C8C8C8'];
                        let rssiLevel = [-5, -10, -20, -25];
                        //var color = "#C8C8C8";
                        let rssi = this.props.rssi;
                        var desc, baseUrl, audioPath, placeHolder;
                        var state = 0;
                        var refImageId = content.contentid;
                        var refAudioId = -1;
                        var exTag = beacon.extag;
                        var fontSize = 20;
                        var lineHeight = 30;
                        var locale = RealmRepo.Locale().displayLang;
                        if(locale=='en' || locale=='pt') {
                            fontSize = 16;
                            lineHeight = 20;
                        }

                        placeHolder = '{' + content.clientpath + content.filename + '}';
                        baseUrl = RNFS.DocumentDirectoryPath + content.clientpath;
                        desc = content["description_" + RealmRepo.Locale().displayLang].replace(placeHolder, content.filename);

                        if (audio) {
                            let audioContent = audio.content;
                            if (audioContent) {
                                refAudioId =  audioContent.contentid;
                                audioPath = RNFS.DocumentDirectoryPath
                                + audioContent.clientpath
                                + audioContent.filename.replace(".mp3", `_${RealmRepo.Locale().voiceLang}.mp3`);
                            }
                        }

                        if (rssi >= effectiveRangeIn) {
                            state = 1;
                        }
                        else if (rssi >= effectiveRangeIn + rssiLevel[0]) {
                            //color = colorLevel[0];
                        }
                        else if (rssi >= effectiveRangeIn + rssiLevel[1]) {
                            //color = colorLevel[1];
                        }
                        else if (rssi >= effectiveRangeIn + rssiLevel[2]) {
                            //color = colorLevel[2];
                        }
                        else if (rssi >= effectiveRangeIn + rssiLevel[3]) {
                            //color = colorLevel[3];
                        }

                        var findBeacon = _.find(beaconState, (o)=> {
                            return o.beaconId == beacon.beaconid;
                        });

                        if (findBeacon) {
                            findBeacon.state = state;
                            if (state == 1) {
                                findBeacon.desc = desc;
                                findBeacon.audioPath = audioPath;
                                findBeacon.baseUrl = baseUrl;
                            }
                        }
                        else {
                            let newBeacon = {
                                beaconId: beacon.beaconid,
                                state: state,
                                mode: 'auto',
                                extag: exTag,
                                refImageId: refImageId,
                                refAudioId: refAudioId,
                                from: 'leftMenuBall'
                            };

                            if (state == 1) {
                                newBeacon.desc = desc;
                                newBeacon.audioPath = audioPath;
                                newBeacon.baseUrl = baseUrl;
                            }

                            beaconState.push(newBeacon);
                        }

                        let bgColor = this.props.altRow ? '#9FADAD': '#88C1C1';

                        return (
                            <TouchableOpacity onPress={()=>{
                                    Actions.detail();
                                    this.eventEmitter('emit','refreshDetail',{
                                        extag: exTag,
                                        refImageId: refImageId,
                                        refAudioId: refAudioId,
                                        desc: desc,
                                        audioPath: audioPath,
                                        baseUrl: baseUrl,
                                        mode: 'manual',
                                        from: 'leftMenuBall'
                                    });
                                }}>
                                <View style={[styles.row,styles.imageView]}>
                                    {/*
                                    <Image source={{
                                        uri:imageUri,
                                        deviceScreen.width,
                                        height:120
                                        }}
                                           resizeMode={Image.resizeMode.stretch}
                                        />*/}
                                    <MyCustView style={{deviceScreen.width-10,height:140}}
                                                textHeight={36}
                                                textFontSize={fontSize}
                                                textFontFamily={'Arial-BoldMT'}
                                                textContent={title}
                                                cropImageWidth={deviceScreen.width-10}
                                                cropImageHeight={140}
                                                srcImagePath={imageUri}/>
                                </View>
                                {/*
                                <View style={[styles.row,styles.descView,{backgroundColor:bgColor}]}>
                                    {title ?
                                        (<Text style={[styles.descText,{fontSize:fontSize,lineHeight:lineHeight}]}>
                                            {title}
                                        </Text>)
                                        : null
                                    }
                                </View>*/}
                            </TouchableOpacity>
                        );
                    }
                }
                else {
                    return null;
                }
            }
            else {
                return null;
            }
        }
        catch (ex) {
            console.log(ex);
            return null;
        }
    }
});

// The BeaconList component listens for changes and re-renders the
// rows (BeaconView components) in that case
var BeaconList = React.createClass({
    mixins:[TimerMixin,EventEmitterMixin],
    getInitialState: function() {
        return {
            dataSource: ds.cloneWithRows([])
        };
    },
    componentDidMount(){
        /*
        this.setInterval(()=> {
            headState = beaconState[0];
            if (!modalState) {
                openHeadState = headState;
            }
            beaconState = _.drop(beaconState);
            if (headState) {
                let user = RealmRepo.getUser();
                //in state
                if (headState.state == 1) {
                    //init
                    if (lastBeaconId == "") {
                        if (History.lastPlayBeaconId != headState.beaconId) {
                            this.stopSound();
                            modalState = true;
                            Actions.detail();
                            this.eventEmitter('emit','refreshDetail',openHeadState);
                            if (user) {
                                RealmRepo.addLog(user.userId, headState.beaconId, '0', headState.extag, ()=> {});
                            }
                            console.log('open', headState.beaconId);
                            lastBeaconId = headState.beaconId;
                            History.lastPlayBeaconId = lastBeaconId;
                        }
                    }
                    else {
                        if (headState.beaconId != lastBeaconId) {
                            //other beacon in
                            //close first
                            modalState = false;
                            this.eventEmitter('emit', 'detailClose');
                            if(user) {
                                RealmRepo.addLog(user.userId, lastBeaconId, '1', headState.extag, ()=> {});
                            }
                            console.log('close', lastBeaconId);
                            lastBeaconId = "";

                            if (History.lastPlayBeaconId != headState.beaconId) {
                                this.setTimeout(()=> {
                                    //then open
                                    this.stopSound();
                                    modalState = true;
                                    Actions.detail();
                                    this.eventEmitter('emit','refreshDetail',openHeadState);
                                    if (user) {
                                        RealmRepo.addLog(user.userId, headState.beaconId, '0', headState.extag, ()=> {});
                                    }
                                    console.log('open', headState.beaconId);
                                    lastBeaconId = headState.beaconId;
                                }, 100);
                                History.lastPlayBeaconId = lastBeaconId;
                            }
                        }
                        else {
                            //the same beacon then keep the state(do nothing)
                        }
                    }
                }
                else {
                    //out state
                    if (lastBeaconId == headState.beaconId) {
                        //the same beacon then close
                        modalState = false;
                        this.eventEmitter('emit', 'detailClose');
                        if(user) {
                            RealmRepo.addLog(user.userId, headState.beaconId, '1', headState.extag, ()=> {});
                        }
                        console.log('close', lastBeaconId);
                        lastBeaconId = ""
                    }
                    else {
                        //do nothing
                    }

                }
            }
        }, 500);*/
    },
    log:function(user,state) {
        //state out-1,in-0
        if(user){
            if(History.playingId) {
                RealmRepo.addLog(user.userId, History.playingId, state, History.lastAccessExTag, ()=> {});
                //console.log(user.userId,History.playingId,state,History.lastAccessExTag);
            }
        }
    },
    triggerPlay:function(major,minor) {
        if (orderState == null) {
            orderState = {
                major: major,
                minor: minor,
                createTime: new Date().getTime()
            };
        }
        else {
            if (orderState.major == major && orderState.minor == minor) {
                var now = new Date().getTime();
                var duration = now - orderState.createTime;
                if (duration >= 3000) {
                    if (History.playingId != major + '-' + minor) {
                        let beacon = RealmRepo.getBeaconInfo(major, minor);
                        if (beacon) {
                            let content = beacon.triggercontent[0].content;
                            let audio = beacon.triggercontent[1];
                            if (content) {
                                let imageUri = RNFS.DocumentDirectoryPath + content.clientpath + content.filename;
                                if (imageUri) {
                                    var desc, baseUrl, audioPath, placeHolder;
                                    var refImageId = content.contentid;
                                    var refAudioId = -1;
                                    var exTag = beacon.extag;

                                    placeHolder = '{' + content.clientpath + content.filename + '}';
                                    baseUrl = RNFS.DocumentDirectoryPath + content.clientpath;
                                    desc = content["description_" + RealmRepo.Locale().displayLang].replace(placeHolder, content.filename);
                                    if (audio) {
                                        let audioContent = audio.content;
                                        if (audioContent) {
                                            refAudioId = audioContent.contentid;
                                            audioPath = RNFS.DocumentDirectoryPath
                                            + audioContent.clientpath
                                            + audioContent.filename.replace(".mp3", `_${RealmRepo.Locale().voiceLang}.mp3`);
                                        }

                                        /*
                                        if (audioPath) {
                                            this.stopSound();
                                            this.playSound(audioPath);
                                        }*/

                                        Actions.detail();
                                        this.eventEmitter('emit', 'refreshDetail', {
                                            extag: exTag,
                                            refImageId: refImageId,
                                            refAudioId: refAudioId,
                                            desc: desc,
                                            audioPath: audioPath,
                                            baseUrl: baseUrl,
                                            mode: 'auto',
                                            from: 'leftMenuBall'
                                        });
                                    }
                                }
                            }
                        }

                        //out
                        let user = RealmRepo.getUser();
                        this.log(user, 1);
                        //current
                        History.playingId = major + '-' + minor;
                        //in
                        this.log(user, 0);
                    }
                }
            }
            else {
                orderState = {
                    major: major,
                    minor: minor,
                    createTime: new Date().getTime()
                };
            }
        }
    },
    componentWillMount: function() {
        this.eventEmitter('on', 'beaconCountChanged', (orderList)=> {
            this.setTimeout(()=> {
                if (orderList) {
                    this.setState({
                        dataSource: ds.cloneWithRows(orderList)
                    });

                    if (orderList.length > 0) {
                        this.triggerPlay(orderList[0].major, orderList[0].minor);
                    }
                    else {
                        //this.stopSound();
                        let user = RealmRepo.getUser();
                        //out
                        this.log(user,1);
                        //History.playingId = null;
                    }
                }
                else {
                    this.setState({
                        dataSource: ds.cloneWithRows([])
                    });
                }
            }, 500);
        });

        this.eventEmitter('on', 'drawerOpenFromBallView', ()=> {
            this.setTimeout(()=> {
                //this.stopSound();
                let user = RealmRepo.getUser();
                //out
                this.log(user,1);
                History.playingId = null;
            }, 1000);
        });

        this.eventEmitter('on', 'action', (param)=> {
            if (param == 'home') {
                this.setTimeout(()=> {
                    //this.stopSound();
                    let user = RealmRepo.getUser();
                    //out
                    this.log(user,1);
                    History.playingId = null;
                }, 1000);
            }
        });
    },
    playSound:function(audioPath) {
        s = new Sound(audioPath, null, (e) => {
            if (e) {
                console.log('error', e);
            } else {
                RNS.headsetDeviceAvailable((v)=> {
                    let user = RealmRepo.getUser();
                    if (user) {
                        if (user.autoPlay == 1) {
                            if (user.earphonePlay == 1) {
                                if (v) {
                                    if (s && s.isLoaded()) {
                                        s.setPan(0);
                                        s.play();
                                    }
                                }
                            }
                            else {
                                if (s && s.isLoaded()) {
                                    s.setPan(0);
                                    s.play();
                                }
                            }
                        }
                    }
                });
            }
        });
    },
    stopSound:function() {
        if (s && s.isLoaded()) {
            s.stop();
            s.release();
        }
    },
    renderRow: function(rowData,sectionID,rowID) {
        return <BeaconView {...rowData} style={styles.row} altRow={rowID%2==0}/>
    },
    renderHeader:function() {
        var title = null;
        let exMaster = (History.lastAccessExTag == '') ? null : RealmRepo.getExMaster(History.lastAccessExTag);
        if (exMaster) {
            let locale = RealmRepo.Locale().displayLang;
            title = exMaster["title_" + locale];
            var trimLength = 25;//en or pt
            if (locale == 'cn' || locale == 'tw') {
                trimLength = 15;//cn or tw
            }
            if (title.length > trimLength) {
                title = title.slice(0, trimLength).concat('...');
            }
        }

        return title ? (<View style={styles.headerView}><Text style={styles.headerText}>{title}</Text></View>) : null;
    },
    render: function() {
        return (
            <View style={styles.container}>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow}
                    renderHeader={this.renderHeader}
                    enableEmptySections={true}
                    />
            </View>
        );
    }
});


var styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'flex-start',
        backgroundColor: '#698686'
    },
    headerView:{
        height:50,
        justifyContent: 'flex-start',
        alignItems: 'center',
        deviceScreen.width
    },
    headerText:{
        fontSize: 25,
        color:'white',
        textAlign:'center'
    },
    headline: {
        fontSize: 20,
        paddingTop: 20
    },
    row: {
        flexDirection: 'row',
        deviceScreen.width,
        padding:5
    },
    imageView: {
        borderRadius: 0,
        overflow: 'hidden'
    },
    descView: {
        alignItems: 'center',
        height:36,
        paddingLeft:2
    },
    descText: {
        fontFamily:'Arial-BoldMT',
        color:'white'
    },
    smallText: {
        fontSize: 11
    },
    modal: {
        justifyContent: 'flex-start',
        alignItems: 'center',
        height: deviceScreen.height,
         deviceScreen.width
    }
});

module.exports = BeaconList;
BeaconList.js

Ref:React Native 初探(iOS) | 不掏蜂窝的熊

Ref:React-Native学习指南 | 蓝戒的博客

原文地址:https://www.cnblogs.com/ncore/p/5614231.html