ReactNativejavascriptReactNative

翻译|React-navigation导航系统(2)

2017-03-29  本文已影响4925人  smartphp

title: 翻译|React-navigation导航系统(2)
date: 2017-03-28 07:48:36
categories: 翻译
tags: React-native


Navigators

Navigators允许你定义你的导航结构.Navigators也可以渲染普通的元素,例如你配置好的header和tab bar.
navigators可以是单纯的React组件.

内建的Navigators

react-navigation包含下面的几个函数帮助你创建navigators:

使用Navigators渲染screen

navigators实际渲染的就是React组件
了解怎么创建screen,读读一下内容:

在顶层组件上调用导航

万一你想在同一级别的Navigation screen之间使用Navigator,你可以使用react的ref选项:

   const AppNavigator = StackNavigator(SomeAppRouteConfigs);

class App extends React.Component {
  someEvent() {
    // call navigate for AppNavigator here:
    this.navigator && this.navigator.dispatch({ type: 'Navigate', routeName, params });
  }
  render() {
    return (
      <AppNavigator ref={nav => { this.navigator = nav; }} />
    );
  }
}

注意:这个解决办法只能用在顶层navigator上.

Navigation Containers

如果navigators没有props的话,他就会表现为顶层navigators.这个方式提供了一个透明的navigator container,这是顶层导航props的来源.
当渲染其中一个navigators的时候,navigation prop是可选的.如果没有navigation prop,container将会管理自己的导航state.他也可以使用URLs,外部链接以及整合android的back button.

为了使用方便,在幕后内建的navigators有这个能力,因为在幕后他们使用了createNavigationContainer.通常,navigators需要一个navigation prop来执行一定的功能.
onNavigationStateChange(prevState, newState)

当navigation state由顶层navigator变化管理的时候,这一点非常有用.为了达到这个目的,这个函数在每次调用的时候都会使用导航之前的state和导航之后的新state作为参数.

containerOptions
当一个navigator在顶层被使用的时候,这些选项可以来配置这个navigator.
如果一个navigator配置了containerOptions,但是也接受了navigationprop,会抛出错误.因为在这种情况下,navigator有两种选择,它就不知道怎么做了.

StackNavigator

给你的app提供screen之间转变的方法,每个转变到的screen会存放在堆栈的栈顶.
默认情况下,StackNavigator配置有iOS和android的外观和感觉:在iOS下,新的screen从屏幕的右侧滑入,在android下,新的screen从底部淡入.iOS下也可以配置为从屏幕底部滑入.

 class MyHomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
  }

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
        title="Go to Lucy's profile"
      />
    );
  }
}

const ModalStack = StackNavigator({
  Home: {
    screen: MyHomeScreen,
  },
  Profile: {
    path: 'people/:name',
    screen: MyProfileScreen,
  },
});

定义API

StackNavigator(Routeconfigs,StackNavigatorConfig)

RouteConfigs

route的配置对象是route name到route config的映射(译者:这才是重点),配置对象告诉navigator什么来代表route.

StackNavigator({

  // 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/:username',
    // The action and route params are extracted from the path.

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

  ...MyOtherRoutes,
});

StackNavigatorConfig

Router的Options:

可视化选项:

Screen Navigation Options

通常在screen组件中定义静态的navigationOptions.例如:

class ProfileScreen extends React.Component {

  static navigationOptions = {

    title: ({ state }) => `${state.params.name}'s Profile!`,

    header: ({ state, setParams }) => ({
      // Render a button on the right side of the header
      // When pressed switches the screen to edit mode.
      right: (
        <Button
          title={state.params.editing ? 'Done' : 'Edit'}
          onPress={() => setParams({editing: state.params.editing ? false : true})}
        />
      ),
    }),
  };
  ...

所有的stackNavigatornavigationOptions:

Navigator Props

StackNavigator(...)创建的navigator组件接收两个props:
screenProps-向下传递到子screen,例如:

 const SomeStack = StackNavigator({
  // config
});

<SomeStack
  screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>

Examples

看看实例SimpleStack.jsModalStack.js,可以在本地的NavigationPlaygroundapp中运行.

TabNavigator

通常很容易使用TabRouter来创建有几个tabs的screen.

class MyHomeScreen extends React.Component {
  static navigationOptions = {
    tabBar: {
      label: 'Home',
      // Note: By default the icon is only shown on iOS. Search the showIcon option below.
      icon: ({ tintColor }) => (
        <Image
          source={require('./chats-icon.png')}
          style={[styles.icon, {tintColor: tintColor}]}
        />
      ),
    },
  }

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.navigate('Notifications')}
        title="Go to notifications"
      />
    );
  }
}

class MyNotificationsScreen extends React.Component {
  static navigationOptions = {
    tabBar: {
      label: 'Notifications',
      icon: ({ tintColor }) => (
        <Image
          source={require('./notif-icon.png')}
          style={[styles.icon, {tintColor: tintColor}]}
        />
      ),
    },
  }

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.goBack()}
        title="Go back home"
      />
    );
  }
}

const styles = StyleSheet.create({
  icon: {
    width: 26,
    height: 26,
  },
});

const MyApp = TabNavigator({
  Home: {
    screen: MyHomeScreen,
  },
  Notifications: {
    screen: MyNotificationsScreen,
  },
}, {
  tabBarOptions: {
    activeTintColor: '#e91e63',
  },
});

定义API

TabNavigator(RouteConfigs,TabNavigator)

RouteConfigs

route的配置对象是route name到route config的映射(译者:这才是重点),配置对象告诉navigator什么来代表route.

TabNavigatorConfig

TabBarToptabBarOptions设置(android默认的tab bar)

实例:

tabBarOptions: {
  labelStyle: {
    fontSize: 12,
  },
  style: {
    backgroundColor: 'blue',
  },
}

Screen导航的选项

通常在screen组件中定义静态的navigationOptions.例如:

 class ProfileScreen extends React.Component {

  static navigationOptions = {

    title: ({ state }) => `${state.params.name}'s Profile!`,

    tabBar: ({ state, setParams }) => ({
      icon: (
        <Image src={require('./my-icon.png')} />
      ),
    }),
  };
  ...

所有TabNavigatornavigationOption:

Navigator Props

TabNavigator(...)创建的navigator组件接收下面的props:

 const TabNav = TabNavigator({
  // config
});

<TabNav
  screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>

抽屉式导航

用来构建抽屉式导航

class MyHomeScreen extends React.Component {
  static navigationOptions = {
    drawer: () => ({
      label: 'Home',
      icon: ({ tintColor }) => (
        <Image
          source={require('./chats-icon.png')}
          style={[styles.icon, {tintColor: tintColor}]}
        />
      ),
    }),
  }

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.navigate('Notifications')}
        title="Go to notifications"
      />
    );
  }
}

class MyNotificationsScreen extends React.Component {
  static navigationOptions = {
    drawer: () => ({
      label: 'Notifications',
      icon: ({ tintColor }) => (
        <Image
          source={require('./notif-icon.png')}
          style={[styles.tabIcon, {tintColor: tintColor}]}
        />
      ),
    }),
  }

  render() {
    return (
      <Button
        onPress={() => this.props.navigation.goBack()}
        title="Go back home"
      />
    );
  }
}

const styles = StyleSheet.create({
  icon: {
    width: 24,
    height: 24,
  },
});

const MyApp = DrawerNavigator({
  Home: {
    screen: MyHomeScreen,
  },
  Notifications: {
    screen: MyNotificationsScreen,
  },
});

打开抽屉或者关闭抽屉,分别导航到DrawerOpenDrawerclose.

this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer

定义API

DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)

RouteConfigs

参看前面的内容

DrawerNavigatonConfig

提供定制化的contentComponent

可以使用react-navigation重写默认的组件.

 const CustomDrawerContentComponent = (props) => (
  <View style={style.container}>
    <DrawerView.Items {...props} />
  </View>
);

const styles = StyleSheet.create({
  container : {
    flex : 1,
  },
});

DrawerView.ItemcontentOptions配置

示例:

 contentOptions: {
  activeTintColor: '#e91e63',
  style: {
    marginVertical: 0,
  }
}

Screen导航的选项

通常在组件中定义静态的navigationOptions.

 class ProfileScreen extends React.Component {

  static navigationOptions = {

    title: ({ state }) => `${state.params.name}'s Profile!`,

    drawer: {
      icon: (
        <Image src={require('./my-icon.png')} />
      ),
    },
  };
  ...

所有的DrawerNavigation navigationOption配置项

Navigator 的Props

DrawerNavigator(...)创建的navigator组件接受下面的props:

 const DrawerNav = DrawerNavigator({
  // config
});

<DrawerNav
  screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>

Screen Navigation Prop

app中的每个screen都接收navigation prop 包含下面的内容:

Navigation Actions

所有的Navigation Actions都会返回一个对象,这个对象可以使用navigation.dispatch方法传递到router.
注意:如果你想dispatch react-navigation,你应该使用这个库提供的action creators.

下面的actions是可以使用的:

Navigate

Navigatie action会使用Navigate action的结果来更新当前的state.

 import { NavigationActions } from 'react-navigation'

const navigateAction = NavigationActions.navigate({

  routeName: 'Profile',

  params: {},

  action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})

this.props.navigation.dispatch(navigateAction)


Reset

Resetaction删掉所有的navigation state并且使用几个actions的结果来代替.

 import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
  index: 0,
  actions: [
    NavigationActions.navigate({ routeName: 'Profile'})
  ]
})
this.props.navigation.dispatch(resetAction)


怎么使用index参数

index参数被用来定制化当前激活的route
例如:使用两个routes ProfileSettings给一个基础的stakc navigation设置.为了重置route到经过Settings的激活screen那一点,但是在堆栈中他又存放在Settingscreen之上,你可以这么做:

import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
  index: 1,
  actions: [
    NavigationActions.navigate({ routeName: 'Profile'}),
    NavigationActions.navigate({ routeName: 'Settings'})
  ]
})
this.props.navigation.dispatch(resetAction)


Back

返回到前一个screen并且关闭当前screen.backaction creator接受一个可选的参数:

import { NavigationActions } from 'react-navigation'

const backAction = NavigationActions.back({
  key: 'Profile'
})
this.props.navigation.dispatch(backAction)

SetParams

当dispatching setParams的时候,router将会产出一个新的state,这个state是已经改变了特定route的参数,以key作为身份验证

 import { NavigationActions } from 'react-navigation'

const setParamsAction = NavigationActions.setParams({
  params: { title: 'Hello' },
  key: 'screen-123',
})
this.props.navigation.dispatch(setParamsAction)

Screen Navigation Options

每个screen都可以配置几个方面的内容,这些内容影响到在父navigators中怎么得到展示.

定制每一个可选项的两种方法

静态配置方法:每一个navigation 可选项都可以被直接设定:

 class MyScreen extends React.Component {
  static navigationOptions = {
    title: 'Great',
  };
  ...

动态配置方法
要么就采用函数式的方法,接受参数,然后返回可选项的值.

 class ProfileScreen extends React.Component {
  static navigationOptions = {
    title: (navigation, childRouter) => {
      return navigation.state.params.name + "'s Profile!";
    },
  };
  ...

通用的Navigation Options

navigation的可选项title在每一个navigator之间是通用的,用来设定每一个screen的标题字符串.

 class MyScreen extends React.Component {
  static navigationOptions = {
    title: 'Great',
  };
  ...

不像其他的navigation的可配置项仅仅由navigator view来使用,title 选项可以被环境变量使用来更新浏览器的标题或者app切换时候的标题.

默认的Navigation选项

在screen中定义navigationOption非常普遍,但是有时候在navigator中定义navitationOptions也是非常有用

想象下面的场景:你的TabNavigator代表app中的一个screen.他在顶层StackNavigator之内:

 StackNavigator:
  - route1: A screen
  - route2: A TabNavigator

现在route2是激活的,你可能会隐藏header,隐藏route1的header非常容易,route2的header应该也很容易隐藏.这就是默认Navigation Option 要做的.可以在navigationOptions中设定:

 TabNavigator({
  profile: ProfileScreen,
  ...
}, {
  navigationOptions: {
     header: {
       visible: false,
     },
   },
 });

提示:你仍然可以在子代导航screen上定制navigationOptions.-例如,上面的ProfileScreen.从screen获得的navigationOptions会和从navigator来的配置按照键-键的方式融合在一起.无论在什么而时间,navigator和screen定义相同的配置(例如:header),screen会优先使用.因此,当ProfileScreen激活的时候,你可以使header再次可见.

扩展默认配置:为了使用screen特定的properties扩展默认配置,而不是重写它,你可以像下面一样配置选项:

 class ProfileScreen extends React.Component {
  static navigationOptions = {
    header: (navigation, defaultHeader) => ({
      ...defaultHeader,
      visible: true,
    }),
  }
  ...
}

传递到函数的第二个参数作为在navigator中定义的header的默认值.

Tab Navigation Options

class TabScreen extends React.Component {

  static navigationOptions = {
    tabBar: ({ state }) => ({
      label: 'Tab Label',
      icon: ({ tintColor }) => (
        <Image
          source={require('./tab-icon.png')}
          style={[styles.icon, {tintColor: tintColor}]}
        />
      ),
      visible: true
    }),
  };

};

Custom Navigation

一个navigator是任何包含router的React组件.这里是一个基本navigator,使用router的API去获得激活组件来渲染

 class MyNavigator extends React.Component {
  static router = MyRouter;
  render() {
    const { state, dispatch } = this.props.navigation;
    const { routes, index } = state;

    // Figure out what to render based on the navigation state and the router:
    const Component = MyRouter.getComponentForState(state);

    // The state of the active child screen can be found at routes[index]
    let childNavigation = { dispatch, state: routes[index] };
    // If we want, we can also tinker with the dispatch function here, to limit
    // or augment our children's actions

    // Assuming our children want the convenience of calling .navigate() and so on,
    // we should call addNavigationHelpers to augment our navigation prop:
    childNavigation = addNavigationHelpers(childNavigation);

    return <Component navigation={childNavigation} />;
  }
}

Navigation Prop

navigation prop传递给navigator的仅仅包含statedispatch,这是当前的navigator的state,但是还有一个事件频道用来发送action request.
所有的navigators都是受控组件:他们总是显示根据props.navigation.state来显示,他们要改变state,唯一的办法是发送actions到props.navigation.dispatch.
Navigators可以通过定制他们的router来改变父navigators的行为.例如,当action应该从router.getStateForAction返回null来阻止其运行的时候.或者一个navigator可以为了定制URI的操作而改写router.getActionForPathParams,为了输出相对navigation action以及操作router.getStateForAction的action.

Navigation State

传递到props.navigation.state的navigation state有下面的结构:

 {
  index: 1, // identifies which route in the routes array is active
  routes: [
    {
      // Each route needs a name, which routers will use to associate each route
      // with a react component
      routeName: 'MyRouteName',

      // A unique id for this route, used to keep order in the routes array:
      key: 'myroute-123',

      // Routes can have any additional data. The included routers have `params`
      ...customRouteData,
    },
    ...moreRoutes,
  ]
}

Navigation Dispatchers

navigator可以dispatch navigation actions,例如Go to URI,Go back.
如果action被成功操作了,dispatcher将会返回true,否则就是false

构建定制navigators的API

为了帮助开发者实施定制navigators,React Navigation提供了下面的工具
createNavigator
这个工具使用标准方法把router和navigation view合并在一起.

 const MyApp = createNavigator(MyRouter)(MyView);

幕后所做的是:

 const MyApp = ({ navigation }) => (
  <MyView router={MyRouter} navigation={navigation} />
);
MyApp.router = MyRouter;

addNavigationHelpers
接收一个拥有statedispatch的纯navigator的prop,传递的参数是在screen navigation prop中的各种函数,例如navigation.navigate()navigation.goBack().这些函数是简单的助手函数帮助创建action并且发送到dispatch.

createNavigationContainer

如果你想让你的navigator作为顶层组件使用(没有navigation prop传入),你可以使用createNavigationContainer.当缺少navigtion prop的时候,这个工具使你的navigator看起来像一个顶层的导航组件.它将管理app的state,和app级别的导航特性整合在一起,例如操作进出的链接和android的返回按钮行为.

上一篇下一篇

猜你喜欢

热点阅读