I am developing a React Native application which uses React Navigation to manage the routing between screens.
I know reading React Navigation documentation and watching this video on Egghead.io (highly suggested) that is possible to define custom animations for transitions between screens passing the transitionConfig
property to a StackNavigator
.
For example, the following code is defining a slide from left animation that is basically the mirror of the iOS default push animation:
const TransitionConfig = () => ({
screenInterpolator: ({ layout, position, scene }) => {
const { index } = scene
const { initWidth } = layout
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [-initWidth, 0, 0],
})
return {
transform: [{ translateX }],
}
}
})
const MyNavigator = createStackNavigator(
{
A: {screen: ScreenA},
B: {screen: ScreenB},
},
{ transitionConfig: TransitionConfig }
)
Considering the code above and the fact we are navigating from screen A
to screen B
, the screenInterpolator
function body is basically describing the animation the screen B
should follow when it's going to appear (it's reverted when it disappears). In this case the code it's saying to translate the screen B
along the X axis to achieve a slide in effect.
Is it possible to also define the animation for the screen that is disappearing (screen A
in our case)? I would like to define something like this:
B
should appear sliding from left to rightA
should disappear sliding from top to bottomI found the answer by myself, I hope will help someone in the future.
I was wrong assuming that screenInterpolator
is describing only the behaviour of the screen B
, because is actually describing the animation of both A
and B
. Or better, it's the interpolate
function with inputRange
and outputRange
that allows you to describe the animation for both the entering (B
) and leaving (A
) screen.
Let's have a closer look to this snippet, keeping in mind that the interpolate
function is just creating a 1-1 association between the values of inputRange
and outputRange
(deeper explanation here).
const { index } = scene
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [-initWidth, 0, 0],
})
Assumptions:
B
and A
are screensA
to B
width(B) = width(A) = 320
width(deviceScreen) = 320
initWidth = 320
Explanation
index-1
represents the screen that is going to appear (screen B
) and it's mapped to -initWidth
. With this we are saying that the screen it's going to appear (screen B
) should be X-translated (respect the viewport) of a value equal its width. So it will start the animation from X = 320
(i.e. outside the screen)index
represents the screen that is going to appear, but once is appeared (still screen B
). Mapping it to 0
we are saying that screen B
once is appeared should be in position X = 0
index + 1
represents the screen once is going to disappear. This is what it led me to the error. At the beginning I thought this was still and only the screen B
, but just when it would have disappeared because of a navigation like B->C
. However from our A->B
point of view, it's the screen A
the one that is going to disappear! So both line of thoughts are correct, it's all about seeing things from a different perspective. So, mapping index+1
to 0
we are saying that screen A
should stay at X=0
when it's going to disappear (i.e. when B
is going to appear)Result
This is the animation realized by the code above. As you can see, the screen A
remains where it is because of the association index+1 <-> 0
(no translation, so no animation for screen A
).
If we change the association of index+1
to index+1 <-> -initWidth
, then screen A
will also be translated and hence animated :)
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [initWidth, 0, -initWidth],
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With