React Navigation: Dynamically setting `mode` setti

2019-07-01 10:31发布

In my app I have three screens: ScreenA, ScreenB and ScreenC. They all should have a header and they should all have a back button with the name of the previous screen. I wanted ScreenA to be able to open ScreenB using the modal animation:

const ModalStack = createStackNavigator(
  {
    ScreenA,
    ScreenB
  },
  {
    initialRouteName: "ScreenA",
    mode: "modal"
  }
);

And ScreenA should also be able to open ScreenC using the default sliding animation from right to left. The problem was, that the StackNavigator was already configured with the modal mode. Is there a way to dynamically set the mode? So that from ScreenA to ScreenB modal is used and from ScreenA to ScreenC card?

Furthermore how to handle the header in this case? (For the reason why I ask this question, please read further.)

Here is what I tried after reading the documentation. It describes a similar scenario.

Here is how this tutorial translated for me:

const SlidingStack = createStackNavigator(
  {
    ScreenA,
    ScreenC
  }
);

const ModalStack = createStackNavigator(
  {
    SlidingStack,
    ScreenB
  },
  {
    mode: "modal"
  }
);

The problem with this solution is, that the header now renders double when I'm on ScreenA. Furthermore when I open the modal ScreenB the back button is blank.

Edit

In my attempt to solve this problem following the documentation, I found a solution for the double header rendering:

const SlidingStack = createStackNavigator(
  {
    ScreenA,
    ScreenC
  }
);

const ModalStack = createStackNavigator(
  {
    SlidingStack,
    ScreenB
  },
  {
    mode: "modal",
    navigationOptions: ({ navigation }) => {
      const options = {}
      if (navigation.state.routeName === "SlidingStack") options["header"] = null;
      return options;
    }
  }
);

The problem with this solution is, that the back buttons still do not have any text.

Edit:

Following what I've learned from Pritish, here is the code I ended up with:

const IOS_MODAL_ROUTES = ["OptionsScreen"];

let dynamicModalTransition = (
  transitionProps: NavigationTransitionProps,
  prevTransitionProps: NavigationTransitionProps
): TransitionConfig => {
  if (
    IOS_MODAL_ROUTES.some(
      screenName =>
        screenName === transitionProps.scene.route.routeName ||
        (prevTransitionProps && screenName === prevTransitionProps.scene.route.routeName)
    )
  ) {
    return StackViewTransitionConfigs.defaultTransitionConfig(
      transitionProps,
      prevTransitionProps,
      true
    );
  }
  return StackViewTransitionConfigs.defaultTransitionConfig(
    transitionProps,
    prevTransitionProps,
    false
  );
};

It uses React Navigation V2's owns transitions.

1条回答
孤傲高冷的网名
2楼-- · 2019-07-01 10:53

Going back to the docs

headerBackTitle:: Defaults to the previous scene's headerTitle

In your implementation, you're trying to move from ScreenA to ScreenB, where the header of the ScreenA is null, therefore the back button doesn't contain a title.

There will always be a case (as per your design) that you transition from a non header screen to a header screen, hence this solution won't work.

A workaround for that would be to create a Transitioner with a default(a screen transition) and modal Transition (a modal transition), and set it in the transitionConfig options of the StackNavigatorConfig as

let CustomTransitionConfig = () => {
    return {
        screenInterpolator: (sceneProps) => {
            const { position, scene } = sceneProps;
            const { index, route } = scene;
            const params = route.params || {};
            const transition = params.transition || 'default';
            return {
                modal: ModalTransition(index, position),
                default: ScreenTransition(index, position),
            }[transition];
        }
    }
};

createStackNavigator({
...
   {transitionConfig: CustomTransitionConfig}
...

and use transition params while navigating if you want to have a modal as

this.props.navigation.navigate({routeName: 'ScreenC', params: {transition: 'modal'}}
查看更多
登录 后发表回答