美文网首页
iOS【react native】尝试一

iOS【react native】尝试一

作者: NJ_墨 | 来源:发表于2017-09-25 20:28 被阅读87次
    #import "React/RCTEventEmitter.h"
    @interface FFRNEventEmitter : RCTEventEmitter
    
    // 导出你所有的方法名字
    - (NSArray<NSString *> *)supportedEvents;
    
    -(void)iseCallback:(NSString*)code result:(NSString*) result;
    -(void)iseVolume:(NSString*)code result:(NSString*) result;
    -(void)playCallback:(NSString*)code result:(NSString*) result;
    
    @property (nonatomic, weak) RCTBridge *bridge;
    
    @end
    
    
    #import "FFRNEventEmitter.h"
    
    
    @implementation FFRNEventEmitter
    @synthesize bridge = _bridge;
    
    RCT_EXPORT_MODULE()
    
    // 导出你所有的方法名字
    - (NSArray<NSString *> *)supportedEvents
    {
      return @[@"iseCallback", @"iseVolume", @"playCallback"];//有几个就写几个
    }
    
    -(void)iseCallback:(NSString*)code result:(NSString*) result
    {
      [self sendEventWithName:@"iseCallback"
                         body:@{
                                @"code": code,
                                @"result": result,
                                }];
    }
    
    -(void)iseVolume:(NSString*)code result:(NSString*) result
    {
      [self sendEventWithName:@"iseCallback"
                         body:@{
                                @"code": code,
                                @"result": result,
                                }];
    }
    
    -(void)playCallback:(NSString*)code result:(NSString*) result
    {
      [self sendEventWithName:@"iseCallback"
                         body:@{
                                @"code": code,
                                @"result": result,
                                }];
    }
    @end
    
    #import <Foundation/Foundation.h>
    #import "FFRNCatgoryListCtrl.h"
    
    @interface FFRNSington : NSObject
    
    + (FFRNSington *)sharedInstance;
    
    @property (nonatomic, weak) FFRNCatgoryListCtrl *RNCatgoryListCtrl;
    @end
    
    
    #import "FFRNSington.h"
    
    @implementation FFRNSington
    
    + (FFRNSington *)sharedInstance
    {
      static FFRNSington *instance = nil;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
      });
      return instance;
    }
    
    @end
    
    #import <Foundation/Foundation.h>
    
    typedef void (^OperateBlock)(id object);
    @interface RNSQLManager : NSObject
    
    @property (nonatomic, copy) OperateBlock operateBlock;
    @end
    
    
    #import "RNSQLManager.h"
    
    @implementation RNSQLManager
    
    - (void)query:(NSString *)queryData successCallback:(OperateBlock)responseSender
    {
       
    }
    @end
    
    #import <UIKit/UIKit.h>
    #import "FFEasyLifeCatagoryModel.h"
    
    #import <React/RCTBridgeModule.h>
    #import <React/RCTLog.h>
    
    #import "React/RCTEventEmitter.h"
    #import "FFRNEventEmitter.h"
    
    @interface FFRNCatgoryListCtrl : UIViewController<RCTBridgeModule>
    @property (nonatomic, strong) FFEasyLifeCatagoryModel *selectModel;
    @end
    
    
    #import "FFRNCatgoryListCtrl.h"
    #import "FFEasyLifeActivityDetailCtrl.h"
    #import "FFEasyLifeCataProduListModel.h"
    
    #import "FFRNSington.h"
    
    #import <React/RCTBundleURLProvider.h>
    #import <React/RCTRootView.h>
    #import <React/RCTBridge.h>
    #import <React/RCTEventDispatcher.h>
    #import <React/RCTEventEmitter.h>
    
    @interface FFRNCatgoryListCtrl ()
    
    @property (strong, nonatomic) YSTopBarView *topBarView;
    @end
    
    @implementation FFRNCatgoryListCtrl
    
    
    RCT_EXPORT_MODULE()
    RCT_EXPORT_METHOD(print:(NSString *)text) {
        
        NSLog(@"---- %@",text);
    }
    
    // 接收传过来的 NSString + NSDictionary
    RCT_EXPORT_METHOD(addEventTwo:(NSString *)name details:(NSDictionary *)details)
    {
        RCTLogInfo(@"接收传过来的NSString+NSDictionary: %@ %@", name, details);
        
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            
            FFEasyLifeCataProduListModel *model = [[FFEasyLifeCataProduListModel alloc] initWithDic:details];
            model.title2 = @"";
            
            FFEasyLifeActivityDetailCtrl *vc = [[FFEasyLifeActivityDetailCtrl alloc] initWithNibName:kFFEasyLifeActivityDetailCtrl bundle:nil];
            vc.actType = model.type;
            vc.idx = model.goodsId;
            vc.activityId = model.activityId;
            
            [[FFRNSington sharedInstance].RNCatgoryListCtrl.navigationController pushViewController:vc animated:YES];
        }];
        
    }
    
    //回调函数,在官方的文档中是有上面的一个警告,不过在使用过程暂时未发现问题。在OC中,我们添加一个getNativeClass方法,将当前模块的类名回调给JS。
    RCT_EXPORT_METHOD(getNativeClass:(RCTResponseSenderBlock)callback) {
        callback(@[NSStringFromClass([self class])]);
    }
    
    
    + (NSArray *)__rct_export__230
    {
        return @[ @"", @"addEvent:(NSString *)name location:(NSString *)location" ];
    }
    
    
    //原生模块可以导出一些常量,这些常量在JavaScript端随时都可以访问。用这种方法来传递一些静态数据,可以避免通过bridge进行一次来回交互。
    //但是注意这个常量仅仅在初始化的时候导出了一次,所以即使你在运行期间改变constantToExport返回的值,也不会影响到JavaScript环境下所得到的结果。
    - (NSDictionary *)constantsToExport {
        return @{ @"BGModuleName" : @"BGNativeModuleExample",
                  @"TestName": @"我是从原生定义的~",
                  };
    }
    
    
    //  对外提供调用方法,演示Callback
    RCT_EXPORT_METHOD(testCallbackEventOne:(NSString *)name callback:(RCTResponseSenderBlock)callback)
    {
        NSLog(@"%@",name);
        NSArray *events=@[@"1", @"2", @"3",@"4"]; //准备回调回去的数据
        callback(@[[NSNull null],events]);
    }
    
    //  对外提供调用方法,演示Promise使用
    RCT_REMAP_METHOD(testCallbackEventTwo,
                     resolver:(RCTPromiseResolveBlock)resolve
                     rejecter:(RCTPromiseRejectBlock)reject)
    {
        NSArray *events =@[@"one ",@"two ",@"three"];//准备回调回去的数据
        if (events) {
            resolve(events);
        } else {
            NSError *error=[NSError errorWithDomain:@"我是Promise回调错误信息..." code:101 userInfo:nil];
            reject(@"no_events", @"There were no events", error);
        }
    }
    
    /**
     注:不知道为什么RN所在的类中self的内存地址会被修改,意思就是你想要的self跟你在于js交互中用到的self不是同一个self.同时出现的情况就会出现pop不掉我们的RN类的这个界面.
     
     解决办法:使用单例来保存我们原本要用的self,在viewDidLoad方法中做保存
     */
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.topBarView = [[YSTopBarView alloc] initWithFrame:CGRectMake(0, 0, k_SCREEN_WIDTH, 64)];
        self.topBarView.leftLabel.text = @"RN_分类";
        [_topBarView.leftButton addTarget:self action:@selector(actionBack) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.topBarView];
        
    //    http://reactnative.cn
        
        
        [FFRNSington sharedInstance].RNCatgoryListCtrl = self;
    
        NSDictionary *props = @{@"cid" : [NSString limitStringNotEmpty:self.selectModel.idx]};
        NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
        RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                            moduleName:@"EasyLife"
                                                     initialProperties:props
                                                         launchOptions:nil];
        rootView.frame = CGRectMake(0, 64, k_SCREEN_WIDTH, k_SCREEN_HEIGHT - 64);
        [self.view addSubview:rootView];
    }
    
    - (void)actionBack {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    @end
    

    js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import {
        SegmentedControlIOS,
        AppRegistry,
        StyleSheet,
        Text,
        Alert,
        FlatList,
        ActivityIndicator,
        Animated,
        ScrollView,
        Image,
        View,
        TouchableOpacity,
    } from 'react-native';
    
    var{NativeModules} =require('react-native');
    var{NativeEventEmitter} =require('react-native');
    
    var FFRNCatgoryListCtrl=NativeModules.FFRNCatgoryListCtrl;
    var FFRNEventEmitter=NativeModules.FFRNEventEmitter;
    const myNativeEvt = new NativeEventEmitter(FFRNEventEmitter);  //创建自定义事件接口
    
    var ITEM_HEIGHT = 100;
    const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
    // const REQUEST_URL = 'https://api.github.com/search/repositories?q=javascript&sort=stars';
    const REQUEST_URL = 'http://192.168.11.23:8086/app-client-web/commodity/searchCommodity.do?&params=%7BcityId:%22%22,sort:%22sales%22,pageSize:20,cid:%227556cb32899248edb5617a722ab0eb53%22,title:%22%22,client_type:2,sys_user_id:%22%22,page:1,desc:1%7D';
    
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: '#F5FCFF',
        },
        welcome: {
            fontSize: 20,
            textAlign: 'center',
            margin: 10,
        },
        instructions: {
            textAlign: 'center',
            color: '#333333',
            marginBottom: 5,
        },
        render: {
            padding: 10,
            paddingTop:20,
            flex: 1,
        },
        icon: {
            marginLeft:10,
            alignItems: 'center',
            width: ITEM_HEIGHT,
            height: ITEM_HEIGHT,
        },
        topicCard: {
            flex: 1,
            flexDirection: 'row',
            padding: 10,
            backgroundColor: '#ffffff',
            borderColor: '#f0f0f0',
            borderStyle: 'solid',
            borderWidth: 1,
            borderRadius: 0
        },
        avatarImg: {
            width: 110,
            height: 110,
            justifyContent:'center',
            borderRadius: 2
        },
        titleMeta: {
            flex: 7,
            marginLeft:15,
            marginRight:10,
            //backgroundColor: 'green',
        },
        topicTitle: {
            marginTop:5,
            fontSize: 16,
            lineHeight: 20,
            fontWeight: 'bold',
            letterSpacing: 1,
            color: '#333333',
            //backgroundColor: '#ff6b13',
        },
        metaarea: {
            flexDirection: 'row',
            marginTop: 10,
            justifyContent: 'flex-start',
            flexWrap: 'wrap',
            //backgroundColor: '#800080',
        },
        metainfo: {
            color: '#999999',
            fontSize: 12,
            lineHeight: 16,
            letterSpacing: 1,
            marginRight: 5
        },
        metaareatag: {
            flexDirection: 'row',
            marginTop: 2,
            justifyContent: 'flex-start',
            flexWrap: 'wrap',
            //backgroundColor: '#556B2F',
        },
        nodename: {
            color: '#999999',
            fontSize: 12,
            lineHeight: 16
        },
        replieCountBg: {
            backgroundColor: '#e74c3c',
            position: 'absolute',
            bottom: 0,
            right: 0,
            paddingBottom: 5,
            paddingTop: 5,
            paddingLeft: 10,
            paddingRight: 10,
            borderRadius: 11
        },
        replieCount: {
            fontSize: 12,
            lineHeight: 12,
            color: '#ffffff',
            fontWeight: 'bold'
        },
    });
    
    
    export default class EasyLife extends Component {
    
        static navigationOptions = {
            title: 'SegmentedControlIOS',
        };
    
        constructor(props) {
            super(props);
            this.state = {
                refreshing: true,
                loadMore: false,
                isLoading: true,
                //网络请求状态
                error: false,
                errorInfo: "",
                dataArray: [],
                sort: "sales",
                desc: 1,
                url: REQUEST_URL,
                index: 0,
                cid: "",
    
            }
    
            // { (this: any).requestData() = this.requestData().bind(this)}
            // { (this: any)._renderCell() = this._renderCell().bind(this)}
            // { (this: any)._header() = this._header().bind(this)}
            // { (this: any)._footer() = this._footer().bind(this)}
    
        }
    
        //渲染完成后调用一次,这个时候DOM结构已经渲染了。这个时候就可以初始化其他框架的设置了,如果利用jQuery绑定事件等等。
        componentDidMount() {
            //请求数据
            this.requestData();
        }
    
    
        //在组件中使用
        componentWillMount() {
            this.listener = myNativeEvt.addListener('iseCallback', this.iseCallback.bind(this));  //对应了原生端的名字
        }
    
        componentWillUnmount() {
            this.listener && this.listener.remove();  //记得remove哦
            this.listener = null;
        }
    
    
        /**
         *
         *   一些事件回调
         *
         * */
        iseCallback(data) {//接受原生传过来的数据 data={code:,result:}
    
            alert('数据');
            if (data.code == CB_CODE_RESULT) {
                //
            }
            else {//..真的是未知的错误
                logf('传回其他参数', data.result);
            }
        }
    
    
    // 传原生一个字符串 + 回调
        callBackOne = () => {
            FFRNCatgoryListCtrl.testCallbackEventOne(('我是RN给原生的'), (error, events) => {
                if (error) {
                    console.error(error);
                } else {
                    this.state.cid = events;
                    this.renderData();
                }
            })
        }
    
    
        callErrorBack = () => {
            // try{
            //     var events=await FFRNCatgoryListCtrl.testCallbackEventTwo();
            //     alert(events)
            // }catch(e){
            //     console.error(e);
            // }
        }
    
    
        //加载等待的view
        renderLoadingView() {
            return (
                <View style={styles.container}>
                    <ActivityIndicator animating={true} style={[styles.gray, {height: 80}]} color='red' size="large"
                    />
                </View>
            );
        }
    
    
        //加载失败view
        renderErrorView(error) {
            return (
                <View style={styles.container}>
                    <Text> Fail: {error} </Text>
                </View>
            );
        }
    
    
        /**
         *
         *  网络请求
         *
         * */
    
        requestData() {
    
            let formData = new FormData();
            var test_url = 'http://192.168.11.23:8086/app-client-web/commodity/searchCommodity.do?';
    
            formData.append("title":"");
            formData.append("cid":"");
            formData.append("cityId":"");
            formData.append("sort":"");
            formData.append("desc":"");
            formData.append("page":"");
            formData.append("pageSize":"");
    
            let params = '&params={cityId:"",sort:"'
                + this.state.sort
                + '",pageSize:20,cid:"'
                + this.state.cid
                + '",title:"",client_type:2,sys_user_id:"",page:1,desc:'
                + this.state.desc + '}';
    
            fetch(test_url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: params,
            })
    
                .then((response) => response.json())
                .then((responseData) => {
                    let data = responseData.resultData.items;
                    let dataBlob = [];
                    let i = 0;
    
                    //遍历data数组中的每个元素,并按照return中的计算方式 形成一个新的元素,放入返回的数组中 如:dataBlob
                    //数组判断
                    if (Array.isArray(data)) {
                        data.map(function (item) {
                            dataBlob.push({
                                key: i,
                                goodsId: item.goodsId,
                                activityId: item.activityId,
                                type: item.type,
                                name: item.name,
                                imgPath: item.imgPath,
                                discountPrice: item.discountPrice,
                                buycount: item.buycount,
                                tempTest: item.tempTest,
                            })
                            i++;
    
                        });
                    }
    
                    this.setState({
                        //复制数据源
                        dataArray: dataBlob,
                        isLoading: false,
                        refreshing: false,
                        loadMore: false,
                    })
    
                    data = null;
                    dataBlob = null;
                });
        }
    
    
        /**
         *
         *  选择事件
         *
         * */
        changeSegment = (event) => {
    
            this.state.index = event.nativeEvent.selectedSegmentIndex;
    
            if (event.nativeEvent.selectedSegmentIndex == 0) {
                this.state.sort = "sales";
                this.state.desc = 1;
    
            } else if (event.nativeEvent.selectedSegmentIndex == 1) {
                this.state.sort = "price";
                this.state.desc = 1;
    
            } else {
                this.state.sort = "price";
                this.state.desc = 0;
            }
    
            //网络请求
            this.requestData();
        }
    
    
    
        /**
         *
         *  按钮事件
         *
         * */
        _onPressItem = (item: Object) => {
            FFRNCatgoryListCtrl.addEventTwo('occ', item);
            //FFRNCatgoryListCtrl.print("Hello World");
        };
    
    
        /**
         *
         *  列表单元格
         *
         * */
        _renderCell = (item) => {
    
            var title = '';
            var discountPrice = '';
            var buycount = '';
            var imgPath = '';
            var tempTest;
    
            var subData;
            if (this.state.dataArray.length > item.index) {
                subData = this.state.dataArray[item.index];
                title = this.state.dataArray[item.index].name;
                discountPrice = '¥' + this.state.dataArray[item.index].discountPrice;
                buycount = '销售指数' + this.state.dataArray[item.index].buycount;
                imgPath = this.state.dataArray[item.index].imgPath;
                if (imgPath.includes('size')) {
                    imgPath = imgPath.replace('size', 'origin');
                }
                tempTest = this.state.dataArray[item.index].tempTest;
            }
    
            return (
                <TouchableOpacity onPress={()=>{this._onPressItem(subData)}}  activeOpacity={0.8}>
                    <View style={styles.topicCard}>
                        <View>
                            <Image style={styles.avatarImg} source={{uri: imgPath}} resizeMode='cover'/>
                        </View>
    
                        <View style={styles.titleMeta}>
                            <Text style={styles.topicTitle} numberOfLines={2}>{title}</Text>
                            <View style={styles.metaarea}>
                                <Text style={styles.metainfo}>{discountPrice}</Text>
                                <Text style={styles.metainfo}>{tempTest}</Text>
                            </View>
    
                            <View style={styles.metaareatag}>
                                {/*<Text style={styles.nodename}>{'occ'}</Text>*/}
                                <View style={styles.replieCountBg}>
                                    <Text style={styles.replieCount}>{buycount}</Text>
                                </View>
                            </View>
                        </View>
    
                    </View>
                </TouchableOpacity>
            );
        }
    
        _header = () => {
            return <Text style={[styles.txt, {backgroundColor: 'white'}]}></Text>;
        }
    
        _footer = () => {
            return <Text style={[styles.txt, {backgroundColor: 'white'}]}></Text>;
        }
    
        _separator = () => {
            return <View style={{height: 2, backgroundColor: 'yellow'}}/>;
        }
    
        /**
         *
         *  刷新事件
         *
         * */
        _onRefresh = () => {
            this.setState({refreshing: true})
            this.requestData();
        }
    
        /**
         *
         * 加载更多 <未实现,有问题>
         *
         * */
        _loadMoreData = () => {
    
            // alert("-- 加载更多");
            // this.state.loadMore = true;
            // this.requestData();
        }
    
    
    
    
        renderData() {
            return (
                <View style={{flex: 1}}>
                    <SegmentedControlIOS
                        //enabled={false}
                        selectedIndex={this.state.index}
                        //momentary={true}
                        onChange={this.changeSegment}
                        tintColor=''
                        values={['按销量排序', '按价格高到低', '按价格低到高']}/>
    
                    <AnimatedFlatList
                        data={this.state.dataArray}
                        ListHeaderComponent={this._header}
                        ListFooterComponent={this._footer}
                        ItemSeparatorComponent={this._separator}
                        renderItem={this._renderCell}
    
                        //如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性。
                        onRefresh={this._onRefresh}
                        refreshing={this.state.refreshing}
                        //当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。
                        //onEndReached={(info) => { alert("滑动到底部了");}}
                        //onEndReached={this._loadMoreData()}
                        //onEndReachedThreshold={100}
                    />
                </View>
            );
        }
    
    
        render() {
    
            //在JS中,我们通过以下方式获取到原生模块的类名
            // FFRNCatgoryListCtrl.getNativeClass(name => {
            //     console.log("nativeClass: ", name);
            //     //alert(name);
            // });
    
            // console.log("FFRNCatgoryListCtrl value is ", FFRNCatgoryListCtrl.TestName);
            //alert(FFRNCatgoryListCtrl.TestName);
    
            //alert(this.props.cid);
    
            this.state.cid = this.props.cid;
    
            //this.callBackOne();
    
            //this.callErrorBack();
    
    
            //第一次加载等待的view
            if (this.state.isLoading && !this.state.error) {
                return this.renderLoadingView();
            } else if (this.state.error) {
                //请求失败view
                return this.renderErrorView(this.state.errorInfo);
            }
            //加载数据
            return this.renderData();
        }
    }
    
    AppRegistry.registerComponent('EasyLife', () => EasyLife);
    
    
    

    相关文章

      网友评论

          本文标题:iOS【react native】尝试一

          本文链接:https://www.haomeiwen.com/subject/icndextx.html