主要是介绍了 react-navigation 的相关配置和样式设置,以及 react-navigation 内的 navigation 属性。navigator 主要分为以下三种类型:StackNavigator、TabNavigator、DrawerNavigator,每种类型都有其相应的使用场景和配置项。

StackNavigator

StackNavigator 组件采用堆栈式的页面导航来实现各个界面跳转。它的构造函数:

StackNavigator(RouteConfigs, StackNavigatorConfig);

有 RouteConfigs 和 StackNavigatorConfig 两个参数。

RouteConfigs

表示各个页面路由配置,类似于前端路由配置页,它是让导航器知道需要导航的路由对应的页面。

const RouteConfigs = {
  Home: {
    screen: HomePage,
    navigationOptions: ({ navigation }) => ({
      title: "首页",
    }),
  },
  Find: {
    screen: FindPage,
    navigationOptions: ({ navigation }) => ({
      title: "发现",
    }),
  },
  Mine: {
    screen: MinePage,
    navigationOptions: ({ navigation }) => ({
      title: "我的",
    }),
  },
};

这里给导航器配置了三个页面,Home、Find、Mine 为路由名称,screen 属性值 HomePage、FindPage、MinePage 为对应路由的页面。

上述代码中的 navigationOptions 是配置对应路由页面的一些属性。

  • title:标题,可当作 headerTitle 的备用的字符串,不推荐使用
  • header:可以设置一些导航的属性,如果隐藏顶部导航栏只要将这个属性设置为 null
  • headerTitle:设置导航栏标题,推荐
  • headerTitleAllowFontScaling:标题栏中字体是否根据字体大小自动缩放设置。 默认为 true。
  • headerBackTitle:iOS 上的返回按钮的文字使用的字符串,或者使用 null 来禁用。默认为上一个页面的 headerTitle。
  • headerTruncatedBackTitle:设置当上个页面标题不符合返回箭头后的文字时(一般是因为文字太多),默认改成”返回”
  • headerRight:设置导航条右侧。可以是按钮或者其他视图控件
  • headerLeft:设置导航条左侧。可以是按钮或者其他视图控件
  • headerStyle:设置导航条的样式。背景色,宽高等
  • headerTitleStyle:设置导航栏文字样式
  • headerBackTitleStyle:设置导航栏‘返回’文字样式
  • headerTintColor:设置导航栏颜色
  • headerPressColorAndroid:安卓独有的设置颜色纹理,需要安卓版本大于 5.0
  • gesturesEnabled:是否支持滑动返回手势,iOS 默认支持,安卓默认关闭
  • gestureResponseDistance:触发滑动返回手势的属性
    • horizontal - 数值型 - 水平方向的距离,默认值 25
    • vertical - 数值型 - 垂直方向的距离,默认值 135.
  • gestureDirection:用来设置关闭页面的手势方向,默认 default 是从做往右,inverted 是从右往左
StackNavigatorConfig

可以通过设置 StackNavigatorConfig,来全局设置 navigator 页面的基本样式和属性

const StackNavigatorConfig = {
  initialRouteName: "Home",
  initialRouteParams: { initPara: "初始页面参数" },
  navigationOptions: {
    title: "标题",
    headerTitleStyle: { fontSize: 18, color: "#666666" },
    headerStyle: { height: 48, backgroundColor: "#fff" },
  },
  paths: "page/main",
  mode: "card",
  headerMode: "screen",
  cardStyle: { backgroundColor: "#ffffff" },
  transitionConfig: () => ({
    screenInterpolator: CardStackStyleInterpolator.forHorizontal,
  }),
  onTransitionStart: () => {
    console.log("页面跳转动画开始");
  },
  onTransitionEnd: () => {
    console.log("页面跳转动画结束");
  },
};
  • initialRouteName:设置默认的页面组件,必须是上面已注册的页面组件
  • initialRouteParams:初始路由参数
  • navigationOptions:用于页面的默认导航选项
  • mode:定义跳转风格
    • card:使用 iOS 和安卓默认的风格
    • modal:iOS 独有的使屏幕从底部画出。类似 iOS 的 present 效果
  • headerMode:返回上级页面时动画效果
    • float:iOS 默认的效果,渲染一个放在顶部的标题栏,并在页面改变时显示动画。 这是 iOS 上的常见模式。
    • screen:渲染一个放在顶部的标题栏,并在页面改变时显示动画。 这是 iOS 上的常见模式。
    • none:无动画
  • cardStyle:自定义设置跳转效果
  • transitionConfig: 自定义设置滑动返回的配置
    • transitionProps - 新页面跳转的属性。
    • prevTransitionProps - 上一个页面跳转的属性
    • isModal - 指定页面是否为 modal。
  • onTransitionStart:当转换动画即将开始时被调用的功能
  • onTransitionEnd:当转换动画完成,将被调用的功能
  • path:路由中设置的路径的覆盖映射配置,path 属性适用于其他 app 或浏览器使用 url 打开本 app 并进入指定页面。path 属性用于声明一个界面路径,例如:【/pages/Home】。此时我们可以在手机浏览器中输入:app 名称://pages/Home 来启动该 App,并进入 Home 界面。
页面内配置

页面的配置选项 navigationOptions 通常还可以在对应页面中去静态配置,比如在 HomePage 页面中:

export default class HomePage extends Component {
  // 配置页面导航选项
  static navigationOptions = ({ navigation }) => ({
    title: "HOME",
    titleStyle: { color: "#ff00ff" },
    headerStyle: { backgroundColor: "#000000" },
  });

  render() {
    return <View></View>;
  }
}

同样地,在页面里面采用静态的方式配置 navigationOptions 中的属性,会覆盖 StackNavigator 构造函数中两个参数 RouteConfigs 和 StackNavigatorConfig 配置的 navigationOptions 里面的对应属性。navigationOptions 中属性的优先级是:页面中静态配置 > RouteConfigs > StackNavigatorConfig

已经配置好导航器以及对应的路由页面了,但是要完成页面之间的跳转,还需要 navigation。

在导航器中的每一个页面,都有 navigation 属性,该属性有以下几个属性/方法:

  • navigate - 跳转到其他页面
  • state - 当前页面导航器的状态
  • setParams - 更改路由的参数
  • goBack - 返回
  • dispatch - 发送一个 action

navigete

调用这个方法可以跳转到导航器中的其他页面,此方法有三个参数:

  • routeName 导航器中配置的路由名称
  • params 传递参数到下一个页面
  • action action

比如:this.props.navigation.navigate(‘Find’, {param: ‘i am the param’});

state

state 里面包含有传递过来的参数 params、key、路由名称 routeName,打印 log 可以看得到:

{
  params: { param: 'i am the param' },
  key: 'id-1500546317301-1',
  routeName: 'Mine'
}

setParams

更改当前页面路由的参数,比如可以用来更新头部的按钮或者标题。

componentDidMount() {
    this.props.navigation.setParams({param:'i am the new param'})
}

goBack

回退,可以不传,也可以传参数,还可以传 null。

this.props.navigation.goBack(); // 回退到上一个页面
this.props.navigation.goBack(null); // 回退到任意一个页面
this.props.navigation.goBack("Home"); // 回退到Home页面复制代码

dispatch

TabNavigator

TabNavigator(RouteConfigs, TabNavigatorConfig);

TabNavigator 配置与 StackNavigator 配置是一样的。

  • screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个 screen 传值和跳转。
  • title:标题,可用作 headerTitle 和 tabBarLabel 回退标题
  • tabBarVisible:是否隐藏标签栏。默认不隐藏(true)
  • tabBarIcon:设置标签栏的图标。需要给每个都设置
  • tabBarLabel:设置标签栏的 title。推荐
  • swipeEnabled:是否允许 tab 页之间滑动切换,如果未设置,则使用 TabNavigatorConfig 的 swipeEnabled 选项
  • tabBarOnPress:tab 被点击时的回调函数;参数是一个对象,包含一下属性:
    • previousScene: { route, index } :正在离开的页面
    • scene: { route, index } 被点击的页面
    • jumpToIndex 执行跳转操作必须的参数
TabNavigatorConfig
  • tabBarComponent - 用作渲染 tab bar 的组件,例如 TabBarBottom(这是 iOS 上的默认设置),TabBarTop(这是 Android 上的默认设置)。
  • tabBarPosition:设置 tabbar 的位置,iOS 默认在底部,安卓默认在顶部。(属性值:’top’,’bottom’)
  • swipeEnabled:是否允许在标签之间进行滑动
  • animationEnabled:是否在更改标签时显示动画
  • configureTransition - 给定 currentTransitionProps 和 nextTransitionProps 的函数,其返回一个配置对象,该对象用于描述 tab 页之间的动画
  • initialLayout - 可以传递包含初始 height 和 width 的可选对象,用以防止 react-native-tab-view 渲染中一个帧的延迟
  • tabBarOptions - Tab 配置属性,用在 TabBarTop 和 TabBarBottom 时有些属性不一致:
    • 用在 TabBarBottom(在 iOS 上的默认 tabBar)
      • activeTintColor:label 和 icon 的前景色 活跃状态下
      • activeBackgroundColor:label 和 icon 的背景色 活跃状态下
      • inactiveTintColor:label 和 icon 的前景色 不活跃状态下
      • inactiveBackgroundColor:label 和 icon 的背景色 不活跃状态下
      • showLabel:是否显示 label,默认开启
      • style:tabbar 的样式
      • labelStyle:label 的样式安卓属性
      • tabStyle - tab 页的样式
      • allowFontScaling - 文本字体大小是否可以缩放取决于该设置,默认为 true。
    • 用在 TabBarTop(在 Android 上的默认 tabBar)
      • activeTintColor:label 和 icon 的前景色 活跃状态下
      • inactiveTintColor:label 和 icon 的前景色 不活跃状态下
      • showIcon:是否显示图标,默认关闭
      • showLabel:是否显示 label,默认开启 style:tabbar 的样式
      • upperCaseLabel - 是否将文本转换为大小,默认是 true
      • pressColor - material design 中的波纹颜色(仅支持 Android >= 5.0)
      • pressOpacity - 按下 tab bar 时的不透明度(仅支持 iOS 和 Android < 5.0).
      • scrollEnabled - 是否允许滑动切换
      • tabStyle - tab 页的样式
      • indicatorStyle - tab 页指示符的样式 (tab 页下面的一条线).
      • labelStyle - tab bar 的文本样式
      • iconStyle - tab bar 的图标样式
      • style - tab bar 的样式
      • allowFontScaling - 文本字体大小是否可以缩放取决于该设置,默认为 true。

几个被传递到底层的路由,用于修改导航逻辑的选项

  • initialRouteName - 第一次加载 tab bar 时路由的 routeName
  • order - 定义了 tab bar 顺序的一个 routeNames 数组
  • paths - 提供 routeName 到 path config 的映射,它覆盖了 routeConfigs 中设置的 path。
  • backBehavior - 返回按钮是否会导致 tab 切换到初始 tab 页? 如果是,则设置为 initialRoute,否则为 none。 默认为 initialRoute。

DrawerNavigator

在原生 Android MD 风格里面很多 app 都会采用侧滑抽屉来做主页面的导航,利用 DrawerNavigator 在 RN 中可以很方便来实现抽屉导航。

DrawerNavigator(RouteConfigs, DrawerNavigatorConfig);

和 DrawerNavigator 的构造函数一样,参数配置也类似。

可以手动去操作抽屉导航

this.props.navigation.navigate("DrawerOpen"); // open drawer
this.props.navigation.navigate("DrawerClose"); // close drawer
this.props.navigation.navigate("DrawerToggle"); // toggle drawer
DrawerNavigatorConfig
  • drawerWidth - 抽屉的宽度
  • drawerPosition - 选项是左或右。 默认为左侧位置
  • contentComponent - 用于呈现抽屉内容的组件,例如导航项。 接收抽屉的导航。 默认为 DrawerItems
  • useNativeAnimations - 是否使用原生动画,默认 true.
  • drawerBackgroundColor - 抽屉的背景色,默认是 white.
  • contentOptions 用来配置抽屉内容的属性。
    • items - 路由数组,可以被修改或者覆盖
    • activeItemKey - 当前选中页的路由的 key
    • activeTintColor - 选中的 DrawerItem 的文本和图标颜色
    • activeBackgroundColor - 选中的 DrawerItem 的背景色
    • inactiveTintColor - 未选中的 DrawerItem 的文本和图标颜色
    • inactiveBackgroundColor - 未选中的 DrawerItem 的背景色
    • onItemPress(route) - DrawerItem 被点击时触发的事件
    • itemsContainerStyle - DrawerItem 容器的样式
    • itemStyle - 每个 DrawerItem 的样式, 可以包含文本或图标
    • labelStyle - 当文本是字符串时,设置 DrawerItem 中文本的样式
    • iconContainerStyle - 用于覆盖 View 图标容器的样式

几个被传递到底层的路由,用于修改导航逻辑的选项

  • initialRouteName - 初始路由的 routeName
  • order - 定义抽屉项目顺序的 routeNames 数组。
  • paths - 提供 routeName 到路径配置的映射,它覆盖 routeConfigs 中设置的路径。
  • backBehavior - 后退按钮是否会切换到初始路由? 如果是,设置为 initialRoute,否则为 none。 默认为 initialRoute 行为

监听事件

let _this = null;

export default class WebViewPage extends Component {
    static navigationOptions = ({ navigation }) => ({
        // ......
                    onPress={() => _this.reload() }>
        // ......
        )
    });
   componentDidMount() {
       _this = this;
   }
    _reload() {
        console.log("aaaaaaa");
    }

应用中的每个页面组件都会自动提供 navigation prop, 该 prop 包含便捷的方法用于触发导航操作, 如下所示:

  • navigate -转到另一个屏幕, 计算出需要执行的操作
  • goBack -关闭活动屏幕并在堆栈中向后移动
  • addListener -订阅导航生命周期的更新
  • isFocused -函数返回 true 如果屏幕焦点和 false 否则。
  • state -当前状态/路由
  • setParams -对路由的参数进行更改
  • getParam -获取具有回退的特定参数
  • dispatch - 向路由发送 action
  • dangerouslyGetParent - 返回父级 navigator 的函数

重要的是要强调 navigation prop 不传递给所有组件; 只有 screen 组件会自动收到此 prop。

this.props.navigation 上有一些取决于当前 navigator 的附加函数

如果是 StackNavigator,除了 navigate 和 goBack ,还提供了如下方法:

  • push - 推一个新的路由到堆栈
  • pop - 返回堆栈中的上一个页面
  • popToTop - 跳转到堆栈中最顶层的页面
  • replace - 用新路由替换当前路由
  • reset 操作会擦除整个导航状态,并将其替换为多个操作的结果。
  • dismiss - 关闭当前堆栈

如果是 DrawerNavigator, 则还可以使用以下选项:

  • openDrawer - 打开
  • closeDrawer - 关闭
  • toggleDrawer - 切换,如果是打开则关闭,反之亦然

通用 API 参考

与 navigation 到大部分操作都涉及到 navigate、goBack、state 、 setParams 和 getParams。

调用此方法可跳转到应用程序中的另一个页面. 可采用以下参数:

navigation.navigate({ routeName, params, action, key });

或者

navigation.navigate(routeName, params, action);
  • routeName - 已在应用程序路由器中某处注册的目标 routeName
  • params - 合并到目标路由的参数
  • action -如果页面是 navigator,则是子路由中运行的子操作,有关支持的操作的完整列表,请参见 Actions Doc
  • key - 要导航到的路由的可选标识符。 如果已存在,将后退到此路由
class HomeScreen extends React.Component {
  render() {
    const { navigate } = this.props.navigation;

    return (
      <View>
        <Text>This is the home screen of the app</Text>
        <Button
          onPress={() => navigate("Profile", { name: "Brent" })}
          title="Go to Brent's profile"
        />
      </View>
    );
  }
}

goBack - 关闭当前页面并返回上一个页面

可以选择提供一个 key, 指定要返回的路由。 默认情况下, goBack 将关闭调用该方法的页面 如果目标是在任何位置返回 *, 而不指定要关闭的内容, 请调用 .goBack(null); 注意, null 参数在嵌套 StackNavigators 的情况下很有用 如果子导航器在堆栈中已经只有一个项目, 则返回父导航器。

class HomeScreen extends React.Component {
  render() {
    const { goBack } = this.props.navigation;
    return (
      <View>
        <Button onPress={() => goBack()} title="Go back from this HomeScreen" />
        <Button onPress={() => goBack(null)} title="Go back anywhere" />
        <Button
          onPress={() => goBack("screen-123")}
          title="Go back from screen-123"
        />
      </View>
    );
  }
}

使用 goBack 从一个指定的页面返回

请记住以下导航堆栈历史记录:

navigation.navigate(SCREEN_KEY_A);
navigation.navigate(SCREEN_KEY_B);
navigation.navigate(SCREEN_KEY_C);
navigation.navigate(SCREEN_KEY_D);

现在你在 * screen D 上,并且想要回到 screen A *(销毁 D、C 和 B)。 然后你需要提供一个 goBack * FROM * 的 key:

navigation.goBack(SCREEN_KEY_B); // 将从 screen B 跳转到 screen A

如果,* screen A * 在堆栈的顶部, 你可以使用 navigation.popToTop()方法。

addListener - 订阅导航生命周期的更新

React Navigation 将事件发送到订阅了它们的页面组件:

  • willFocus -页面将获取焦点
  • didFocus - 页面已获取到焦点(如果有过渡动画,等过渡动画执行完成后响应)
  • willBlur - 页面将失去焦点
  • didFocus - 页面已获取到焦点(如果有过渡动画,等过渡动画执行完成后响应)
const didBlurSubscription = this.props.navigation.addListener(
  "didBlur",
  (payload) => {
    console.debug("didBlur", payload);
  }
);

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

JSON 格式的参数:

{
  action: { type: 'Navigation/COMPLETE_TRANSITION', key: 'StackRouterRoot' },
  context: 'id-1518521010538-2:Navigation/COMPLETE_TRANSITION_Root',
  lastState: undefined,
  state: undefined,
  type: 'didBlur',
};

你也可以用 组件 以声明的方式订阅导航事件。

isFocused - 查询页面是否获取到焦点

如果页面已获取到焦点,则返回 true 否则返回 false。

let isFocused = this.props.navigation.isFocused();

您可能希望使用 withNavigationFocus 而不是直接使用此方法, 它将传入一个布尔型的 prop – isFocused 到你的组件。

state - 当前的 state 或 route

页面可以通过 this.props.navigation.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' }
}

通过 navigatesetParams 方法传入参数。是获取页面参数最常用的方法。

class ProfileScreen extends React.Component {
  render() {
    return Name: {this.props.navigation.state.params.name};
  }
}

setParams - 对路由的参数进行更改

触发setParams方法允许页面更改路由中的参数,这对于更新标题按钮和标题文本很有用。 setParams 就像 React 的 setState -他会将原来的参数与现在的参数合并

class ProfileScreen extends React.Component {
  render() {
    return (
      <Button
        onPress={() => this.props.navigation.setParams({ name: "Lucy" })}
        title="Set title name to 'Lucy'"
      />
    );
  }
}

getParam - 获取指定的的参数,可设置获取失败的返回值

过去, 当 params 未定义时, 你可能在获取 params 时遇到问题。 现在,你不必直接访问参数,可以调用 getParam 方法。

之前:

const { name } = this.props.navigation.state.params;

如果 params 未定义, 则此操作失败

现在:

const name = this.props.navigation.getParam("name", "Peter");

如果 name 或 param 未定义, 则返回 Peter。

Stack Actions

下列操作将在所有 stack navigator 中起作用:

  • Push

类似于 navigate, push 将跳转到堆栈中的新的路由 与 navigate 的区别在于,如果有已经加载的页面,navigate 方法将跳转到已经加载的页面,而不会重新创建一个新的页面。 push 总是会创建一个新的页面,所以一个页面可以被多次创建

navigation.push(routeName, params, action);
  • routeName - 已在应用程序路由器中某处注册的目标 routeName
  • params - 合并到目标路由的参数
  • action -如果页面是 navigator,则是子路由中运行的子操作,有关支持的操作的完整列表
  • Pop - 返回到堆栈中的上一个页面,如果提供一个参数 n,则指定在堆栈内返回几层。
navigation.pop(n);
  • PopToTop

调用该方法将直接跳转到堆栈最顶层的路由,销毁其它所有页面。

navigation.popToTop()

  • Replace

调用该方法将使用指定的路由覆盖当前的页面,可以附带参数(params 和 sub-action)

navigation.replace(routeName, params, action)

  • Reset

操作会擦除整个导航状态,并将其替换为多个操作的结果。

navigation.reset([NavigationActions.navigate({ routeName: ‘Profile’ })], 0)

  • Dismiss

如果你想关闭整个 stack 回到父级 stack 中,调用这个方法

navigation.dismiss()

虽然 dispatch 方法并不常用,但是当使用 navigate 和 goBack 无法满足要求时,该方法会是个不错的选择。

  • dispatch - 向路由发送 action

使用 dispatch 将任何导航操作发送到路由后,该操作都将具有最高优先级。

请注意,如果您想分发 react-navigation 操作,则应使用此库中提供的操作创建者。

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);
  • dangerouslyGetParent - get parent navigator

例如,如果您有一个可以在多个导航器中显示的屏幕组件,则可以使用此组件根据其所在的导航器来影响其行为。

另一个很好的用例是在父路由列表中查找活动路由的索引。 因此,如果您在索引 0 处于堆栈的情况下,那么您可能不想渲染后退按钮,但如果您在列表中的其他位置,那么您将渲染后退按钮。

请务必始终检查调用是否返回有效值。

class UserCreateScreen extends Component {
  static navigationOptions = ({ navigation }) => {
    const parent = navigation.dangerouslyGetParent();
    const gesturesEnabled =
      parent &&
      parent.state &&
      parent.state.routeName === "StackWithEnabledGestures";

    return {
      title: "New User",
      gesturesEnabled,
    };
  };
}