This is highly requested and it would be very convenient. Need to outline the use cases, how some hypothetical new API would look and how it would improve over the current way to do this with separate stacks. Also, are there things we cannot currently do without screen-specific transitions?
react-navigation/react-navigation#2585 includes a link to several issues about this.
Copied over from @satya164's post on react-navigation/react-navigation#3217:
Recently I needed to customize screen transition animation for a single screen and it wasn't really straightforward. This proposal aims to provide a simple and straightforward way to specify screen transition for a single screen.
There is an existing proposal react-navigation/react-navigation#175, but it looks very confusing and difficult to use.
Problem
Currently, to be able to customize screen transition for a specific screen, you need to configure it globally and it's not very intuitive. It looks something like this:
navigationOptions: {
transitionSpec: {
duration: 200,
},
transitionConfig: () => ({
screenInterpolator: props => {
// Transitioning to search screen (navigate)
if (props.scene.route.routeName === 'Search') {
return CardStackStyleInterpolator.forFade(props);
}
const last = props.scenes[props.scenes.length - 1];
// Transitioning from search screen (goBack)
if (last.route.routeName === 'Search') {
return CardStackStyleInterpolator.forFade(props);
}
return CardStackStyleInterpolator.forHorizontal(props);
},
}),
}
It's kinda weird and also doesn't allow me to specify a different duration for the back transition.
Proposal
When customizing the transition for a specific screen, we would want to customize 2 different transitions:
- Animation when navigating to the screen
- Animation when going back from the screen
For both animations, we should be able to specify which style properties should be animated, e.g. opacity
, transform
or both, also control the duration of both animations individually. We should also be able to specify transitions for the header buttons.
Keeping these in mind, the following would work for the above scenario:
type TransitionConfigurator = (
toTransitionProps: TransitionProps,
fromTransitionProps: TransitionProps) => {
transitionSpec?: NavigationTransitionSpec,
screenInterpolator?: Object,
headerLeftInterpolator?: Object,
headerTitleInterpolator?: Object,
headerRightInterpolator?: Object,
}
This differs from the current type definition https://github.com/react-navigation/react-navigation/blob/master/src/TypeDefinition.js#L522 and therefore is a breaking change. However, it's possible to support both styles and deprecate the old style gradually without breaking existing code.
This also changes the behavior so that:
- Empty object (
screenInterpolator: {}
) will disable transition animations for any property (I think this is the current behavior too)
null
/undefined
(screenInterpolator: null
) will use the default transition animations (this is a new behavior)
Basically, this proposal aims to keep the semantics as close to the previous semantics but changes the way the options are specified to be more flexible.
Usage example
navigationOptions: {
transitionConfig: (toTransitionProps, fromTransitionProps) => {
const isBack = fromTransitionProps.navigation.state.index >= toTransitionProps.navigation.state.index;
const routeName = isBack ? fromTransitionProps.scene.route.routeName : toTransitionProps.scene.route.routeName;
// This check is only for the case where the transitionConfig is specified globally per navigator basis
// If the config is specified per screen basis, then `routeName` will always refer to the current screen
if (routeName === 'Search') {
return {
transitionSpec: { duration: isBack ? 150 : 200 },
screenInterpolator: CardStackStyleInterpolator.forFade(props),
}
}
},
}
Options specified per screen will always take priority over options specified globally.
When navigation from ScreenA
-> ScreenB
, the transitionConfig
option on both screens are called with the same set of arguments, i.e. toTransitionProps.scene
refers to ScreenB
and fromTransitionProps
refers to ScreenA
. However, the config returned from ScreenA.navigationOptions.transitionConfig
is applied only to ScreenA
and the config returned from ScreenB.navigationOptions.transitionConfig
is applied only to ScreenB
.