Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal Transitions on iOS #262

Closed
mpiannucci opened this issue Jul 11, 2019 · 16 comments

Comments

Projects
None yet
2 participants
@mpiannucci
Copy link

commented Jul 11, 2019

On iOS, it is common to have new views pop modally over the current context instead of pushing a detail view. I tried to look into how I could implement this but before I changed much I wanted to see if there was a suggested way of doing this.

On iOS, when you modally present it introduces a new UINavigation flow so its not a super trivial change

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 11, 2019

PS. I love this library, its exactly what I was looking for as a native dev coming to RN. I have another pull request incoming some point today to introduce more styling of NavigationBarIOS and TabBarIOS

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 11, 2019

I’m chuffed you like the Navigation router. It means a lot coming from a native dev. I’m looking forward to your PR because styling was next on my todo list!

Thanks for the question. The Modal component from React Native does show a new UIViewController. Is that what you’re after or do you mean that you want to present a new UINavigationController?

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 11, 2019

Great... just ironing out some bugs later and ill send it along.

I would love to be able to embed a Navigation stack inside of a new view controller presented modally and I was not sure if it is currently possible to do that using the existing Modal RN component. I know you can do it in RNN.

One use case would be launching a settings view, but then being able to push to a detail view from the main settings list for more detailed selections. Let me know if Im not being clear and I can find a video of what I am talking about.

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 11, 2019

Something that might work on iOS (not Android) is to treat the Modal the same way we treat the main navigation flow. So create a new StateNavigator for your modal flow and start it off in the 'settings' scene.

var modalNavigator = new StateNavigator([
  {key: 'settings'},
  {key: 'detail', trackCrumbTrail: true}
]);

modalNavigator.navigate('settings');

Render the 'settings' scene, using the navigator from Context to navigate to the 'detail' scene.

var {settings, details} = modalNavigator.states;
settings.renderScene = () => (
  <NavigationContext.Consumer>
    {({stateNavigator}) => (
      <TouchableHighlight
        onPress={() => {
          stateNavigator.navigate('detail');
        }}>
        <Text>Detail</Text>
      </TouchableHighlight>
    )}
  </NavigationContext.Consumer>
);

details.renderScene = () => <Details />

Then render a NavigationStack inside the Modal component.

<Modal>
  <NavigationHandler stateNavigator={modalNavigator}>
    <NavigationStack />
  </NavigationHandler>
</Modal>

I haven’t tried this out but it sounds promising. Let me know how you get on (don’t suffer in silence).

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 11, 2019

Whaddaya know, it actually works!

The only problem I found was that when I swiped/pressed back, the onDidNavigateBack fired on both the Modal NavigationStack and the main NavigationStack. So if you navigated back to 'settings' on the Modal it also navigated back to the beginning of the main stack!

It’s because events bubble in React Native (I never realised that). The Modal stack is inside the main stack and so the 'back' event bubbles up from Modal to main.

The fix is to stop the event bubbling by calling stopPropagation in onDidNavigateBack of NavigationStack

onDidNavigateBack(event) {
  event.stopPropagation();
  var {nativeEvent} = event;
  ...

I won’t do a PR for this yet because you might find other problems. We’ll put a PR together once you’re happy that everything works for your use-case.

If you have any trouble getting it working just give me a shout.

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 12, 2019

Thanks for the details! I will try to work up a full test case this weekend and see how it goes!

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 14, 2019

No need to call stopPropgation. The correct way to stop the event bubbling is to register the event as RCTDirectEventBlock instead of RCTBubblingEventBlock.

// NVNavigationStackManager.m
RCT_EXPORT_VIEW_PROPERTY(onDidNavigateBack, RCTDirectEventBlock)

We should make the same change for the onPress event of the TabBar so that they can be nested inside a Modal, too.

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 14, 2019

Okay great thanks for the info! I can make those changes in my fork and include them with #263 if you want?

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 14, 2019

Let's make a separate PR for the Modal fixes

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 16, 2019

I changed to DirectEvents and had no problems using NavigationStack or TabBarIOS components inside of a Modal component. Of course, if you have any problems, feel free to re-open.

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 16, 2019

Awesome!! Thank you so much!

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 17, 2019

Okay so I just tried this out finally. It definitely works, but it doesn’t quite manage to hit the native functionality I am looking. On iOS, when you present a modal view controller you by default get a smooth slide from the bottom of the screen. In iOS 12 this is an even bigger deal and swipe gestures are built in to dismiss the modal assuming they slide in from the bottom.

I think this can be accomplished by defining an extra property on navigate possibly, but I will look around tomorrow to see if I can find how react-native-navigation manages to handle it.

Here is an example of the functionality as shown in the DarkSky app https://i.imgur.com/m5mXq3q.mp4

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 17, 2019

The Modal component isn’t part of the Navigation router. It comes with React Native. It does use the native functionality on iOS. For example, you can get a smooth slide from the bottom of the screen by setting the animationType to "slide".

<Modal
  animationType="slide"
  transparent={false}
  visible={true}>
</Modal>
@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 17, 2019

Just released navigation-react-native v5.3.1!

@mpiannucci

This comment has been minimized.

Copy link
Author

commented Jul 17, 2019

Yeah I know its not part of this library. I was a little confused because the other nav libraries have it as part of their API. Sorry for the stupid questions, still getting used to where to find things I would find natively in RN!

@grahammendick

This comment has been minimized.

Copy link
Owner

commented Jul 17, 2019

Hey, it wasn’t a stoopid question! I think the current navigation libraries have caused a lot of confusion by including Modals in their APIs. The Navigation router concentrates on navigation and leaves it up to React Native to handle Modals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.