react-navigation (v2) 初级

本文是在react-navigation v2版本基础上编辑的。中文文档传送口

为了便于牢记react-navigation的功能,我将其分成了几个小块:

  • StackNavigator
    堆栈导航
  • Tab Navigator
    Tab菜单
  • Drawer Navigator
    侧边栏菜单
  • SwitchNavigator
  • navigation
    navigation属性
  • withNavigation
    传递navigation
  • android物理返回键重写
  • Stack navigator、Tab navigator等相互嵌套
  • SafeAreaView

1.StackNavigator

stack navigator 为你的应用提供了一种在屏幕之间切换并管理导航历史记录的方式。 如果您的应用程序只使用一个 stack navigator ,则它在概念上类似于Web浏览器处理导航状态的方式 - 当用户与它进行交互时,应用程序会从导航堆栈中新增和删除页面,这会导致用户看到不同的页面。 Web浏览器和 React Navigation 工作原理的一个主要区别是:React Navigation 的 stack navigator 提供了在 Android 和 iOS 设备上,在堆栈中的路由之间导航时你期望的手势和动画。

创建一个stack navigator
通过createStackNavigator(RouteConfigs, StackNavigatorConfig)函数,返回一个React组件。

RouteConfigs:

createStackNavigator({
  // For each screen that you can navigate to, create a new entry like this:
  Profile: {
    // `ProfileScreen` is a React component that will be the main content of the screen.
    screen: ProfileScreen,
    // When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.

    // Optional: When deep linking or using react-navigation in a web app, this path is used:
    path: 'people/:name',
    // The action and route params are extracted from the path.

    // Optional: Override the `navigationOptions` for the screen
    navigationOptions: ({ navigation }) => ({
      title: `${navigation.state.params.name}'s Profile'`,
    }),
  },

  ...MyOtherRoutes,
});

screen添加到stack navigation中时,以key:object的形式添加,key必须唯一,object必须属性:screen,选配属性path、navigationOptions。此处的navigationOptions是针对本screen的配置。

StackNavigatorConfig:


react-navigation (v2) 初级_第1张图片
StackNavigatorConfig
  • initialRouteName:设置堆栈的默认屏幕。 必须匹配路由配置中的某个 Key。
  • initialRouteParams: 初始路由的参数
  • navigationOptions: 用于屏幕的默认导航选项。是对stack navigator内所有screen的配置,可重写。
  • mode: 定义渲染和转换的样式;
    card - 使用标准的 iOS 和 Android 屏幕转换。 这是默认设置。
    modal -使屏幕从底部滑动, 这是一个常见的 iOS 模式。仅在 iOS 上工作, 对 Android 没有影响。
  • headerMode: 指定标题栏的呈现方式:
    float -呈现一个位于顶部的单个标题栏, 并在屏幕被更改时进行动画显示。这是 iOS 上常见的模式。
    screen -每个屏幕都有一个标头, 并且标题栏随屏幕一起淡入和淡出。这是 Android 的常见模式。
    none -不会呈现标题栏。

2. Tab Navigator

屏幕底部的一个简单的选项卡栏, 可以在不同的路由之间切换。路由被懒加载--他们的屏幕组件在第一次聚焦之前不会载入。(以底部选项卡进行说明)

react-navigation (v2) 初级_第2张图片
tab navigator
  • 创建方式:有三种,分别对应了底部选项卡栏、屏幕底部的材料设计主题标签栏、屏幕顶部的材料设计主题标签栏。
  • initialRouteName:第一次加载时初始选项卡路由的 routeName。
  • order:定义选项卡顺序的 routeNames 数组。
  • backBehavior:控制 "返回" 按钮是否会导致 Tab 页切换到初始 Tab 页? 如果是, 设置为 initialRoute, 否则 none。 默认为 initialRoute的行为。
  • tabBarComponent: -可选,覆盖用作标签栏的组件。
  • BottomTabNavigatorConfig:tabbar配置选项。
  • navigationOptions:导航器内部的navigationOptions。

示例代码:

const MineStack = createStackNavigator(
    {
        Mine:MineScreen,
        Setting:SettingScreen
    }
)

const HomeStack = createStackNavigator(
    {
        Home:HomeScreen
    }
)

const TabNavigator = createBottomTabNavigator(
    {
        Home2:HomeStack,
        Detail: DetailScreen,
        Mine: MineStack,
    }
)

需要注意的是,TabNavigator中的tab页面是没有标题栏的。

3. Drawer Navigator

侧边抽屉式菜单导航。

react-navigation (v2) 初级_第3张图片
drawer navigator
  • drawerWidth:抽屉的宽度或返回它的函数。

  • drawerPosition:选项为 左 或 右. 默认值为 左 位置。

  • contentComponent:用于呈现抽屉内容 (例如, 导航项) 的组件。 接收用于抽屉的 navigation 支柱。 默认为 DrawerItems。

  • contentOptions:配置抽屉内容

  • useNativeAnimations:启用本机动画。默认值为 true。

  • drawerBackgroundColor:使用某种颜色的抽屉背景。默认值为 白色。

  • initialRouteName:第一次加载时初始选项卡路由的 routeName。

  • order:定义选项卡顺序的 routeNames 数组。

  • backBehavior:控制 "返回" 按钮是否会导致 Tab 页切换到初始 Tab 页? 如果是, 设置为 initialRoute, 否则 none。 默认为 initialRoute的行为。

  • navigationOptions:页面导航选项.

  • title:可用作headerTitle和tabBarLabel的后备的通用标题。

  • drawerLabel:字符串,React 元素或给定{focused:boolean,tintColor:string}的函数返回一个React.Node,以显示在抽屉边栏中。 未定义时,使用场景title

  • drawerIcon:React 元素或给定{ focused: boolean, tintColor: string }的函数返回一个 React.Node,用于在标签栏中显示。

  • drawerLockMode:指定抽屉的锁定模式。 这也可以通过在顶级路由器上使用 screenProps.drawerLockMode 动态更新。

  • open/close:通过navigation的api开启/关闭drawer navigator。

4. SwitchNavigator

SwitchNavigator的目的是一次只显示一个屏幕。默认情况下,它不处理返回操作,并在你切换时将路由重置为默认状态。

react-navigation (v2) 初级_第4张图片
SwitchNavigator
  • initialRouteName:第一次加载时初始选项卡路由的 routeName。
  • resetOnBlur:切换离开屏幕时,重置所有嵌套导航器的状态。 默认为true。
  • backBehavior:控制 "返回" 按钮是否会导致 Tab 页切换到初始 Tab 页? 如果是, 设置为 initialRoute, 否则 none。 默认为none行为。

5. Navigation Prop

重要的是要强调导航道具没有传递到所有组件;只有屏幕组件自动接收navigation!

react-navigation (v2) 初级_第5张图片
Navigation Prop
  • navigate:转到另一个屏幕,如果已存在,转到已存在的屏幕,如果不存在,则增加。
navigation.navigate({routeName, params, action, key})
navigation.navigate(routeName, params, action)
  • addListener:订阅导航生命周期的更新。
    React Navigation发射事件以屏幕订阅它们的组件:willBlur、willFocus、didFocus、didBlur
const didBlurSubscription = this.props.navigation.addListener(
  'didBlur',
  payload => {
    console.debug('didBlur', payload);
  }
);

// Remove the listener when you are done
didBlurSubscription.remove();

The JSON payload:

{
  action: { type: 'Navigation/COMPLETE_TRANSITION', key: 'StackRouterRoot' },
  context: 'id-1518521010538-2:Navigation/COMPLETE_TRANSITION_Root',
  lastState: undefined,
  state: undefined,
  type: 'didBlur',
};
  • isFocused:如果屏幕聚焦则返回true,否则返回false。
  • state:屏幕的当前状态/路由
{
  // the name of the route config in the router
  routeName: 'profile',
  //a unique identifier used to sort routes
  key: 'main0',
  //an optional object of string options for this screen
  params: { hello: 'world' }
}
  • dispatch:向路由器发送一个动作
import { NavigationActions } from 'react-navigation';

const navigateAction = NavigationActions.navigate({
  routeName: 'Profile',
  params: {},

  // navigate can have a nested navigate action that will be run inside the child router
  action: NavigationActions.navigate({ routeName: 'SubProfileRoute' }),
});
this.props.navigation.dispatch(navigateAction);
  • push:添加新路由到堆栈,不管堆栈中是否已有相同key的路由。
navigation.push(routeName, params, action)
  • pop:带你到堆栈中的前一个屏幕。如果您提供一个数字“n”,它将指定多少屏幕将您带回堆栈。
navigation.pop(n)
  • popToTop:将其调用以跳回堆栈中的顶部路径,关闭所有其他屏幕。。
  • replace:用新的路由替换当前的路由。
navigation.replace(routeName, params, action)

如果当前导航器是堆栈导航器,navigation prop才具有额外的 push、pop、popToTop、replace。

6. withNavigation

withNavigation是一个高阶组件,它可以将 navigation 这个 prop 传递到一个包装的组件。 当你无法直接将navigation 这个 prop 传递给组件,或者不想在深度嵌套的子组件中传递它时,它将非常有用。
withNavigation (Component)返回一个Component

import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';

class MyBackButton extends React.Component {
  render() {
    return 

7. android物理返回键重写

默认情况下,当用户按下 Android 物理返回键时,react-navigation 会返回到新页面,如果没有可返回的页面,则退出应用。 这是一个合理的默认行为,但有些情况下你可能想要实现自定义处理。

推荐的第三方依赖:react-navigation-backhandler

我的方式是:定义BaseComponent,需要重写android返回键的,集成该组件。

let lastBackPressed = 0;

export default class BaseComponent extends Component {

    _didFocusSubscription;
    _willBlurSubscription;

    constructor(props) {
        super(props);
        this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
            BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
        );
    }

    componentDidMount() {
        this._willBlurSubscription = this.props.navigation.addListener('willBlur', payload =>
            BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
        );
    }

    componentWillUnmount() {
        this._didFocusSubscription && this._didFocusSubscription.remove();
        this._willBlurSubscription && this._willBlurSubscription.remove();
    }

    onBackButtonPressAndroid = () => {
        let now = new Date().getTime();
        if(now - lastBackPressed < 2500) {
            return false;
        }
        lastBackPressed = now;
        ToastAndroid.show('再点击一次退出应用',ToastAndroid.SHORT);
        return true;
    };

}

其中使用到了navigation的addListener属性。
onBackButtonPressAndroid返回true,则react-navigation将不会接收到返回事件,当返回false时,react-navigation将处理返回事件,返回上个路由或者退出应用。

8. Stack navigator、Tab navigator等相互嵌套

navigator之间的相互嵌套示例:

const DrawNavigator = createDrawerNavigator(
    {
        Draw1:DrawScreen1,
        Draw2: DrawScreen2,
    }
)

const MineStack = createStackNavigator(
    {
        Mine:MineScreen,
        Setting:SettingScreen
    }
)

const HomeStack = createStackNavigator(
    {
        Home:HomeScreen
    }
)

HomeStack.navigationOptions={tabBarLabel: 'Home!',}

//****stack navigator嵌套在Tab navigator中
const TabNavigator = createBottomTabNavigator(
    {
        Home2:HomeStack,
        Detail: DetailScreen,
        Mine: MineStack,
    },

)

TabNavigator.navigationOptions = {header:null}

//****Draw navigator 和Tab navigator 嵌套在stack navigator中
const RootStack = createStackNavigator(
    {
        Draw:DrawNavigator,
        Tab: TabNavigator
    },{
        initialRouteName: 'Tab',
    }
);


export default class App extends React.Component {
    
    render() {
        return ;
    }

}

关注下TabNavigator.navigationOptions = {header:null}代码设置,其效果是将父navigator(stack navigator)的标题栏隐藏。
Why?
TabNavigator是一个React组件,TabNavigator.navigationOptions配置的是TabNavigator组件的的导航配置,是相对于父navigator(组件)的导航配置。我们其称之为TabNavigator外部navigationOptions
那么内部的navigationOptions如何理解呢?

TabNavigator的内部navigationOptions指的是tab navigator包含的组件(screen)中的tabBar相关的configs(tab navigator包含的screen是没有标题栏的)。那么tabNavigator的内部navigationOptions该如何设置呢?示例代码如下:

const TabNavigator = createBottomTabNavigator(
    {
        Home2:HomeStack,
        Detail: DetailScreen,
        Mine: MineStack,
    },{
        navigationOptions:{
            title:'Test'
        }
    }

)

上述代码中navigationOptions是针对TabNavigator内部所有的screen而言,可在screen中重写效果。

关于外部navigationOptions内部navigationOptions的概念,同样适用于其他navigator,如HomeStack.navigationOptions={tabBarLabel: 'Home!',},HomeStack是Tab navigator的包含的一个组件,外部的navigationOptions就是设置这个组件的tabbar配置。

9. SafeAreaView

默认情况下,React Navigation 会帮助确保您的应用程序在iPhoneX上正确显示。 它通过在可能与传感器集群(“齐刘海”)或 Home 主页指示器交互的UI元素内部使用SafeAreaView来实现。

当我们隐藏/自定义导航栏或选项卡栏时,可能存在以下问题:


react-navigation (v2) 初级_第6张图片
错误示例

Landscape Mode(横屏模式)时,可能的错误:


react-navigation (v2) 初级_第7张图片
错误示例

此时,我们可以 通过使用SafeAreaView包装内容,避免这些问题。示例代码如下:

import { SafeAreaView } from 'react-navigation';

class App extends Component {
  render() {
    return (
      
        
          This is top text.
        
        
          This is bottom text.
        
      
    );
  }
}

使用 forceInset 获得更多控制
在某些情况下,你可能需要更多控制应用哪些填充。 例如,你可以通过将forceInset 这个 prop 传递给SafeAreaView来移除底部填充。


  
    This is top text.
  
  
    This is bottom text.
  

forceInset使用 key(取值:top | bottom | left | right | vertical | horizontal)和value(取值:'always' | 'never')组成一个对象 或者,您可以通过传递一个整数来完全重写填充。

你可能感兴趣的:(react-navigation (v2) 初级)