The Modal docs say to use Navigator instead of Modal with a top-level Navigator. However, when setting backgroundColor: 'transparent' on the scene being pushed, the previous scene is not visible below. So how do we actually go about simulating a Modal with Navigator?
If there's a way to do this already then I'd be willing to create a PR to update the docs to reflect that.
Closing to ask on StackOverflow first.
@fender did you ever solve this issue? I'm having the same problem. Thanks
@udfalkso I followed this blog post: http://browniefed.com/blog/2015/10/18/react-native-easy-overlay-modal-with-navigator/
@fender Thanks! Seems to work well enough.
This still feels like a bug in Navigator that should get solved properly. I'd consider re-opening the issue.
+1 for re-opening. We should know if this an intended behaviour or its a bug in navigator.
Yeah this should be a supported feature. I think it'd be hard to automatically infer if a scene is opaque but we could have a flag on the route.
I think this won't be fixed in the current version of Navigator -- a new version of Navigator is in progress though so stay tuned :)
@ide - shall we close this?
Hi there! This issue is being closed because it has been inactive for a while.
But don't worry, it will live on with ProductPains! Check out its new home: https://productpains.com/post/react-native/navigator-scene-with-transparent-background-doesnt-show-previous-scene
ProductPains helps the community prioritize the most important issues thanks to its voting feature.
It is easy to use - just login with GitHub.
Also, if this issue is a bug, please consider sending a PR with a fix.
We're a small team and rely on the community for bug fixes of issues that don't affect fb apps.
I modified navigator's code in react native and reached the goal.
You only need to take the following two steps:
``` js
{
// No gestures.
gestures: {},
// Actually, I don't know this.
springFriction: 26,
// Decrease animation time, look like in a moment.
springTension: 500,
// Actually, I don't know this.
defaultTransitionVelocity: 1,
animationInterpolators: {
// animation of this route's coming in
into: buildStyleInterpolator({
opacity: {
value:1,
type:'constant',
},
}),
// animation of previous route's going out
// This is the key: previous view no position change, no opacity change.
out: buildStyleInterpolator({
opacity: {
value:1,
type:'constant',
},
}),
},
},
```
If you do not do this, the previous view will move to the bottom of the screen.
``` js
_disableScene: function(sceneIndex) {
let sceneConstructor = this.refs['scene_' + sceneIndex];
let nextRoute = this.state.routeStack[sceneIndex + 1];
if (nextRoute && nextRoute.opts && nextRoute.opts.isPreViewStatic) {
sceneConstructor.setNativeProps({
pointerEvents: 'none',
});
} else {
sceneConstructor.setNativeProps(SCENE_DISABLED_NATIVE_PROPS);
}
},
```
So, I made a Popup without Modal. Actually, this is a route, you can close this route in Android by pressing the back button.

What I want to know is how to config the duration of Navigator's animation when push or pop a route?
I tweaked the above comment a bit and submitted it as a #7682. Changing the scene configs isn't _necessary_, though arguably nice to have. I left it out of that PR since I didn't want to potentially duplicate each Float* config just to remove the scaling transition.
@seansfkelley Please see the PR through, this is very useful :)
@dragonwong I thoughts, to change the duration of Navigator's animation should be updating the file of
CustomComponents/Navigator/NavigatorSceneConfigs.js
ModalFloatFromBottom: {
...BaseConfig,
gestures: {},// none gestures handling
//defaultTransitionVelocity: 2,
springTension: 700,
animationInterpolators: {
into: buildStyleInterpolator(FromTheFront),
out: buildStyleInterpolator(ModalPrevFixed),
},
},
Additionally,
it is necessary to add '{isPreViewStatic: true}', such as this.props.navigator.push({pageType: "modal-pop", opts:{isPreViewStatic: true}}) , since the file CustomComponents/Navigator/Navigator.js is updated, nextRoute.opts.isPreViewStatic.
@dragonwong Hello, I have modified your solution a bit to be simpler if you just want to hard encapsulate a certain transition to not hide the parent component, this can be useful for more people
var SCENE_DISABLED_NATIVE_PROPS_VISIBLE = {
pointerEvents: 'none',
};
_disableScene: function(sceneIndex) {
let sceneConstructor = this.refs['scene_' + sceneIndex];
let nextRoute = this.state.routeStack[sceneIndex + 1];
var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
if (sceneConfig == Navigator.SceneConfigs.FloatFromBottom ) {
sceneConstructor.setNativeProps(SCENE_DISABLED_NATIVE_PROPS_VISIBLE);
} else {
sceneConstructor.setNativeProps(SCENE_DISABLED_NATIVE_PROPS);
}
},
@samzanemesis I've tried your code. It work like a charm. Thanks to @dragonwong and others. You all are awesome guys.
@dragonwong Your solution is a great place to start. However I applied it a little bit differently:
_disableScene: function(sceneIndex) {
let sceneConstructor = this._sceneRefs[sceneIndex];
let nextRoute = this.state.routeStack[sceneIndex + 1];
if (nextRoute && nextRoute.isPreViewStatic) {
sceneConstructor.setNativeProps({
pointerEvents: 'none',
});
} else {
sceneConstructor.setNativeProps(SCENE_DISABLED_NATIVE_PROPS);
}
},
This was so I just need to pass isPreViewStatic somewhere in the route object to trigger it.
One thing I noticed with this is when unmounting the component that I had this on, caused a re-render of the previous component causing the screen to flicker (more visible with transparent components)
In order to prevent that rerender I made the following change as well:
_enableScene: function(sceneIndex) {
// First, determine what the defined styles are for scenes in this navigator
var sceneStyle = flattenStyle([styles.baseScene, this.props.sceneStyle]);
// Then restore the pointer events and top value for this scene
var enabledSceneNativeProps = {
pointerEvents: 'auto',
style: {
top: sceneStyle.top,
bottom: sceneStyle.bottom,
},
};
if (sceneIndex !== this.state.transitionFromIndex &&
sceneIndex !== this.state.presentedIndex) {
// If we are not in a transition from this index, make sure opacity is 0
// to prevent the enabled scene from flashing over the presented scene
enabledSceneNativeProps.style.opacity = 0;
}
let sceneConstructor = this._sceneRefs[sceneIndex];
let nextRoute = this.state.routeStack[sceneIndex + 1];
if (nextRoute && nextRoute.isPreViewStatic) {
sceneConstructor.setNativeProps({
pointerEvents: 'auto',
});
} else {
sceneConstructor.setNativeProps(enabledSceneNativeProps);
}
},
Thanks @dragonwong @samzanemesis for the contribution
@dragonwong @ivanbrens Thanks for your solutions, it works, resolve my questions, I hope RN will support it in the future, so that we do not need to change source code.
Most helpful comment
I modified navigator's code in react native and reached the goal.
You only need to take the following two steps:
``` js
{
// No gestures.
gestures: {},
},
```
If you do not do this, the previous view will move to the bottom of the screen.
``` js
_disableScene: function(sceneIndex) {
let sceneConstructor = this.refs['scene_' + sceneIndex];
let nextRoute = this.state.routeStack[sceneIndex + 1];
},
```
So, I made a Popup without Modal. Actually, this is a route, you can close this route in Android by pressing the back button.
What I want to know is how to config the duration of Navigator's animation when push or pop a route?