React-Native--01 从React-Navigation开始

从React-Navigation开始

如何创建一个iOS 上面NavigationController + UITabBarController的架构?

直接开始撸代码,撸完再解释:
今天目标是:
1.创建一个工程(今天是2019年4月1日,是最新的React-native version是0.59)
2.查看工程目录
3.导入React-Navigation
4.开始项目编写主界面和子页面
5.开始搭建NavigationController + UITabBarController架构
6.运行项目
7.总结

1.创建一个工程(今天是2019年4月1日,是最新的react-native version是0.59)

到你想创建工程的文件夹路径下,执行如下代码

/**
 * react-native init 固定写法,初始化
 * NavigationProject 工程名字,随便起,无关大雅
 */
$react-native init NavigationProject

image.png

注意:网络好的情况下几十秒就创建完成了

2.查看工程目录

image.png

android:这是android项目的入口
iOS:这是iOS项目的入口
node_modules:用于存放node.js包,里面是一些js的库
.js:项目文件,用于存放逻辑处理,界面代码的
.json:配置性的文件
注:跨平台项目都会生成多个工程入口去对应不同的平台

index.js:相当于原生开发中的main文件,工程的入口,App.js就是一个界面(这里用的是vs code)

image.png

3.导入React-Navigation

image.png

拉起vscode底下蓝色状态栏目部分,选择TERMINAL这一项,这里相当于你的终端,输入:

$yarn add react-navigation
# 或者使用 npm
# $npm install --save react-navigation

等待下载完毕,查看yarn.lock文件中是否存在了React-navigation相关的配置

下列两个步骤一定要去添加

$yarn add react-native-gesture-handler
# or with npm
# $npm install --save react-native-gesture-handler

Link的原生依赖

$react-native link react-native-gesture-handler

对于Android工程,在Android中的MainActivity.java

import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;


@Override
protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
    @Override
    protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
        }
    };
}

image.png

如果开发混编App需要到工程里面去做相应的配置,请参考官网
++ https://reactnavigation.org/docs/zh-Hans/getting-started.html ++

代码编写

1.stack navigator的使用

stack navigator:简单理解就是iOS中的UINavigationController,负责页面的跳转,导航;是一个先进后出的栈。

1.配置一个NavigationContainer
通过:createStackNavigator()这个方法来创建一个NavigationContainer

// 源码
export function createStackNavigator(
    routeConfigMap: NavigationRouteConfigMap,
    stackConfig?: StackNavigatorConfig
): NavigationContainer;

创建一个NavigationContainer需要两个参数:
routeConfigMap:路由配置地图,简单来说可以预先添加几个界面

// 通过源码来查看routeConfigMap
// NavigationRouteConfigMap
export interface NavigationRouteConfigMap {
    [routeName: string]: NavigationRouteConfig;
}

// NavigationRouteConfig
export type NavigationRouteConfig =
    | NavigationComponent
    | ({
        navigationOptions?: NavigationScreenConfig<any>;
        path?: string;
    } & NavigationScreenRouteConfig
);

// NavigationScreenRouteConfig
export type NavigationScreenRouteConfig =
    | NavigationComponent
    | {
        screen: NavigationComponent;
      }
    | {
        getScreen: () => NavigationComponent;
      };

由源码我们可以知道routeConfigMap是一个字符串:一个路由配置构成
可以简单理解为

{字符串(表示路由名字):路由配置}

NavigationRouteConfig:配置是的可以接收三种类型的入参

第一种,传入一个extends NavigationComponent的组建

第二种, 传入{navigationOptions?:NavigationScreenConfig;path?: string};
NavigationScreenConfig:导航页面的相关配置
path:路径

第三种,一个返回NavigationComponent组建的方法

stackConfig?:栈的配置

// StackNavigatorConfig
export interface StackNavigatorConfig
    extends NavigationStackViewConfig,
      NavigationStackRouterConfig {
    containerOptions?: any;
}

// NavigationStackViewConfig
export interface NavigationStackViewConfig {
    mode?: 'card' | 'modal';
    headerMode?: HeaderMode;
    headerBackTitleVisible?: boolean;
    headerTransitionPreset?: 'fade-in-place' | 'uikit';
    headerLayoutPreset?: 'left' | 'center';
    cardShadowEnabled?: boolean;
    cardOverlayEnabled?: boolean;
    cardStyle?: StyleProp<ViewStyle>;
    transparentCard?: boolean;
    transitionConfig?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps: NavigationTransitionProps,
      isModal: boolean
    ) => TransitionConfig;
    onTransitionStart?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps?: NavigationTransitionProps
    ) => Promise<void> | void;
    onTransitionEnd?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps?: NavigationTransitionProps
    ) => void;
}

// NavigationStackRouterConfig
export interface NavigationStackRouterConfig {
    headerTransitionPreset?: 'fade-in-place' | 'uikit';
    initialRouteName?: string;
    initialRouteParams?: NavigationParams;
    paths?: NavigationPathsConfig;
    defaultNavigationOptions?: NavigationScreenConfig<NavigationScreenOptions>;
    navigationOptions?: NavigationScreenConfig<NavigationScreenOptions>;
    initialRouteKey?: string;
}

一个简单例子

1.创建两个界面Index(index.js),Details(details.js)

2.编写App.js,至于Index.js(这个是系统的,为了和系统区分,我这里用了一个index,小写的)无需做任何更改;

// 导入createAppContainer, createStackNavigator两个方法
import { createAppContainer, createStackNavigator } from 'react-navigation';
// 这是我创建的两个界面
import Index from './component/index/index.js';
import Details from './component/details/details.js';

// 通过createStackNavigator创建一个NavigationContainer
const AppNavigator = createStackNavigator({
  Home: {
    screen: Index,
  },
  Details: {
    screen: Details,
  },
}, {
    initialRouteName: 'Home',
});

// 通过createAppContainer创建一个可以导出的NavigationContainer
export default createAppContainer(AppNavigator);

上述的操作,让很多无法理解createStackNavigator()和createAppContainer()创建出来的类型都是一样的
理论上我们可以写下这样代码:

import React, {Component} from "react"
import { createAppContainer, createStackNavigator } from 'react-navigation';
import Index from './component/index/index.js';
import Details from './component/details/details.js';

const AppNavigator = createStackNavigator({
  Home: {
    screen: Index,
  },
  Details: {
    screen: Details,
  },
}, {
    initialRouteName: 'Home',
});

export default class App extends Component {
  render(){
    return (
        <AppNavigator />
    );
  }
}

// export default createAppContainer(AppNavigator);

啪一下,运行报错了

image.png

报错的信息,是

Invariant Violation: The navigation prop is missing for this navigator. In react-navigation 3 you must set up your app container directly. 

换言之,就是固定写法,react-navigation 3采用的第一种方式,我当时的想法是错误的。

index.js

import React, {Component} from 'react'
import {
    View,
    Text,
    StyleSheet
} from 'react-native'

export default class Index extends Component {
    render() {
        return (
            <View style={styles.container}>
              <Text style={styles.welcome}>Welcome to React Native!</Text>
              <Text style={styles.instructions }
                    onPress={()=>{this.props.navigation.navigate('Details')}}
              >To get started, edit Index.js</Text>
            </View>
        ); 
    }
}

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,
    },
});
  

details.js


import React, {Component} from 'react'
import {
    View,
    Text,
    StyleSheet
} from 'react-native'

export default class Details extends Component {
    render() {
        return (
            <View style={styles.container}>
              <Text style={styles.welcome}>Welcome to React Native!</Text>
              <Text style={styles.instructions} 
                    onPress={()=>{this.props.navigation.navigate('Home')}}
              >go to home </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.goBack()}
              > go back </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.push('Details')}
              > go to new details </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.navigate('Details')}
              > go to details </Text>
            </View>
        ); 
    }
}

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,
    },
});
  

查看结果:
StackNavigator.gif

我们可以打印一下this.props

// 在render()方法返回之前添加打印代码
console.log("\n details this.props", this.props);

image.png

这里我们可以看见在props中有navigation的属性,换言之,在栈里面的页面就会有一个有值的navigation属性

安利一个调试方式

网上很多教程使用chrome浏览器进行调试,对于小白来说这种调试方式很不友好,很多iOS或者Android转过来的童鞋们还是习惯的IDE里面去看报错信息。让vs code可以打印js log
1.调试操作

image.png

2.添加调试
image.png

1.这里需要注意的是,开始调试之前,请关掉之前打开调试,否则它显示调试正在进行,无法启动。

2.Android 模拟器无法启动,并提示路径不对,请将生成Android文件导入Android Studio中,Android Studio将帮你完成余下配置

3.心细的童鞋可能会发现我的界面有些不同,是因为我在准备截图的期间去换一次主题和换了一个目录,前面几张截图是之前截下来的,所以会有些写出入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值