【React Native】iOS原生导航跳转RN页面

上一篇介绍了React Native使用react-navigation进行导航跳转页面,现在我们介绍下原生iOS中怎么导航进一个新的React Native页面。

一、原生跳转React Native

  1. 创建HYReactNativeManager管理类.

在HYReactNativeManager.h中声明实现声明RCTBridgeDelegate协议,并声明一个全局bridge的属性

@interface HYReactNativeManager : NSObject<RCTBridgeDelegate>

+ (instancetype)shareInstance;

// 全局唯一的bridge
@property (nonatomic, readonly, strong) RCTBridge *bridge;

@end

在HYReactNativeManager.m中实现单例方法、初始化方法、RCTBridgeDelegate协议方法:

#import "HYReactNativeManager.h"

@implementation HYReactNativeManager

static HYReactNativeManager *_instance = nil;
+ (instancetype)shareInstance{
    if (_instance == nil) {
        _instance = [[self alloc] init];
    }
    return _instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    if (_instance == nil) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
    }
    return _instance;
}

-(instancetype)init{
    if (self = [super init]) {
        _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
    }
    return self;
}

#pragma mark - RCTBridgeDelegate
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
# if DEBUG
        return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"
                                                              fallbackResource:nil];
# else
    return [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"jsbundle"];
#endif
}

@end
  1. 创建HYReactNativeBaseViewController类,作为新React Native页面的容器类,实现便捷创建方法:

HYReactNativeBaseViewController.h完整代码如下:

#import <UIKit/UIKit.h>

@interface HYReactNativeBaseViewController : UIViewController

/**
 传递到React Native的参数
 */
@property (nonatomic, strong) NSDictionary * initialProperty;

/**
 React Native界面名称
 */
@property (nonatomic, copy) NSString * pageName;

+ (instancetype)RNPageWithName:(NSString*)pageName initialProperty:(NSDictionary*)initialProperty;

- (instancetype)initWithPageName:(NSString*)pageName initialProperty:(NSDictionary*)initialProperty;

@end

HYReactNativeBaseViewController.m完整代码如下:

#import "HYReactNativeBaseViewController.h"
#import <React/RCTRootView.h>
#import "HYReactNativeManager.h"

@implementation HYReactNativeBaseViewController

+ (instancetype)RNPageWithName:(NSString*)pageName initialProperty:(NSDictionary*)initialProperty{
    HYReactNativeBaseViewController *vc = [[HYReactNativeBaseViewController alloc] initWithPageName:pageName initialProperty:initialProperty];
    return vc;
}

- (instancetype)initWithPageName:(NSString*)pageName initialProperty:(NSDictionary*)initialProperty{
    if(self = [super init]){
        self.pageName = pageName;
        self.initialProperty = initialProperty;
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:YES];
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.navigationController setNavigationBarHidden:NO];
}

-(void)viewDidLoad{
    [super viewDidLoad];
    
    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:[HYReactNativeManager shareInstance].bridge
                                                     moduleName:self.pageName
                                              initialProperties:self.initialProperty];
    self.view = rootView;
}

@end

  1. 将首页按钮点击事件改为:
- (void)clickButton:(UIButton*)button{
    HYReactNativeBaseViewController *vc = [[HYReactNativeBaseViewController alloc] initWithPageName:@"Navigator" initialProperty:@{}];
    [self presentViewController:vc animated:YES completion:nil];
}

二、React Native返回原生

  1. 创建HYModule类,实现RCTBridgeModule协议
    HYModule.h代码:
#import <React/RCTBridgeModule.h>

@interface HYModule : NSObject<RCTBridgeModule>

@end

.m代码:

#import "HYModule.h"

@implementation HYModule

RCT_EXPORT_MODULE()

- (dispatch_queue_t)methodQueue {
    return dispatch_get_main_queue();
}

RCT_EXPORT_METHOD(navigateBack){
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HYModuleNavigateBack" object:nil];
}

@end
  1. 在HYReactNativeBaseViewController.m中添加HYModuleNavigateBack事件监听
@implementation HYReactNativeBaseViewController

//...省略代码
- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)navagateBack{
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)viewDidLoad{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(navagateBack) name:@"HYModuleNavigateBack" object:nil];

    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:[HYReactNativeManager shareInstance].bridge
                                                     moduleName:self.pageName
                                              initialProperties:self.initialProperty];
    self.view = rootView;
}
@end

在RN页面中,调用导入HYModules并调用HYModules.navigateBack()方法即可通过导航返回页面:

import React, { Component } from 'react';
import {StyleSheet, Image, Text, Button,View, FlatList,TouchableOpacity,NativeModules} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation'

var REQUEST_URL = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0"
var HYModules = NativeModules.HYModule

class LogoTitle extends React.Component {
  render() {
    return (
      <Image
        source={require('../image/movie.png')}
        style={{ width: 30, height: 30 }}
      />
    );
  }
}

export default class HotMovie extends Component<Props> {
  

  static navigationOptions = {
     headerTitle: <LogoTitle />,
     headerLeft: (
      <Button
        onPress={() => HYModules.navigateBack()}
        title="首页"
        color="#fff"
      />
    ),
  };

  _onItemClick(item) {
    this.props.navigation.navigate('Details',{itemId:item.id,cover:item.cover,title:item.title})
  }

  constructor(props){
    super(props);
    this.state = {
      movies:null,
    }

    this.renderMovie = this.renderMovie.bind(this)
    this.fetchData = this.fetchData.bind(this)
  }

  componentDidMount(){
    this.fetchData()
  }

  fetchData(){
    fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          movies:responseJson.subjects
        });
      })
  }

  render() {
    if (!this.state.movies) {
      return this.renderLoadingView();
    }
    return (
      <FlatList
        data={this.state.movies}
        renderItem={this.renderMovie}
        style={styles.list}
        keyExtractor={item => item.id}
      />
    );
  }


  renderLoadingView(){
    return (
      <View style={styles.container}>
        <Text>
          正在加载...
        </Text>
      </View>
    )
  }


  renderMovie({item}){
    return(
      <TouchableOpacity style={styles.item} onPress={() => this._onItemClick(item)}>
        <Image source={{url:item.cover}} style={styles.thumbnail}/>
        <View style={styles.itemRight}>
          <Text>{item.title}</Text>
          <Text>{item.rate}</Text>
        </View>
      </TouchableOpacity>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex:1,
    flexDirection:'row',
    alignItems:'center',
    justifyContent: 'center',
    alignItems: 'center',
  },
  item:{
    marginTop:1,
    flexDirection:'row',
    alignItems:'center',
    justifyContent: 'flex-start',
    height:100,
    backgroundColor:'lightgray',
    paddingLeft:10
  },
  thumbnail:{
    width:53,
    height:81,
    backgroundColor:'lightgray'
  },
  itemRight:{
    height:100,
    justifyContent: 'center',
    alignItems:'center',
    paddingLeft:10
  },
  list: {
    backgroundColor: "#F5FCFF"
  }
});



完整源代码:https://github.com/dolacmeng/RNProject/tree/master
在这里插入图片描述

发布了103 篇原创文章 · 获赞 55 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/dolacmeng/article/details/90452050