18

I'd like to use React Navigation in my new react native app but I can't find any example showing how to create custom view transitions in there. Default transitions are working fine but I'd like to be able to customize them in few places and the docs don't come very helpfull in this subject. Anyone tried that already? Anywhere I could see a working example? Thanks in advance.

Rocky Balboa
  • 1,456
  • 2
  • 13
  • 21

1 Answers1

74

You can find detailed version of this post on this link

I hope this is clear enough with step-by-step for how to create custom transition.

Create a Scene or Two to navigate

class SceneOne extends Component {
    render() {
        return (
            <View>
                <Text>{'Scene One'}</Text>
            </View>
        )
    }
}
class SceneTwo extends Component {
    render() {
        return (
            <View>
                <Text>{'Scene Two'}</Text>
            </View>
        )
    }
}

Declare your app scenes

let AppScenes = {
    SceneOne: {
        screen: SceneOne
    },
    SceneTwo: {
        screen: SceneTwo
    },
}

Declare custom transition

let MyTransition = (index, position) => {
    const inputRange = [index - 1, index, index + 1];
    const opacity = position.interpolate({
        inputRange,
        outputRange: [.8, 1, 1],
    });

    const scaleY = position.interpolate({
        inputRange,
        outputRange: ([0.8, 1, 1]),
    });

    return {
        opacity,
        transform: [
            {scaleY}
        ]
    };
};

Declare custom transitions configurator

let TransitionConfiguration = () => {
    return {
        // Define scene interpolation, eq. custom transition
        screenInterpolator: (sceneProps) => {

            const {position, scene} = sceneProps;
            const {index} = scene;

            return MyTransition(index, position);
        }
    }
};

Create app navigator using Stack Navigator

const AppNavigator = StackNavigator(AppScenes, {
    transitionConfig: TransitionConfiguration
});

Use App Navigator in your project

class App extends Component {
    return (
        <View>
            <AppNavigator />
        </View>
    )
}

Register your app in eq. index.ios.js

import { AppRegistry } from 'react-native';
AppRegistry.registerComponent('MyApp', () => App);

Update #1

As for the question on how to set transition per scene, this is how I'm doing it.

When you navigate using NavigationActions from react-navigation, you can pass through some props. In my case it looks like this

this.props.navigate({
    routeName: 'SceneTwo',
    params: {
        transition: 'myCustomTransition'
    }
})

and then inside the Configurator you can switch between these transition like this

let TransitionConfiguration = () => {
    return {
        // Define scene interpolation, eq. custom transition
        screenInterpolator: (sceneProps) => {

            const {position, scene} = sceneProps;
            const {index, route} = scene
            const params = route.params || {}; // <- That's new
            const transition = params.transition || 'default'; // <- That's new

            return {
                myCustomTransition: MyCustomTransition(index, position),
                default: MyTransition(index, position),
            }[transition];
        }
    }
};
Tim Rijavec
  • 1,770
  • 22
  • 27
  • 1
    That's pretty imressive. It all just works great. Thank you for such detailed answer. There's just one little typo in your code, so the line: const { position } = sceneProps; should be: const { position, scene } = sceneProps; Thanks again. – Rocky Balboa May 15 '17 at 23:23
  • @karol.barkowski Thanks mate, I appreciate it. Typo fixed! – Tim Rijavec May 16 '17 at 07:48
  • 1
    @TimRijavec Do you have any idea how I can change transition for individual screen? – Sagar Khatri May 27 '17 at 08:24
  • @SagarKhatri please see my updated answer for that under Update #1 and do like it. – Tim Rijavec May 27 '17 at 10:11
  • @TimRijavec Thanks for your time. I really appreciate. It's just I know the one method to navigate using `this.props.navigation.navigate('ScreenName')` and your solution has `this.props.navigate` how to use it? Moreover is it also useful while resetting the route? Like my scenario is clicking on Login will take to private area. – Sagar Khatri May 29 '17 at 05:26
  • @TimRijavec. It worked. Just there is one minor miss in your code. Please edit your answer and replace `const {index} = scene;` with `const {index, route} = scene;` – Sagar Khatri May 29 '17 at 10:20
  • @SagarKhatri I'm binding navigation.navigate to the props directly hence I'm using navigate and you are using navigation.navigate (same thing) – Tim Rijavec May 29 '17 at 11:03
  • @TimRijavec Great. I think you should post your answer to ReactNavigation github issue. Lot of people have the same problem. – Sagar Khatri May 29 '17 at 15:05
  • @TimRijavec in your Update #1 example, how would you set that up so that default: would use the standard CardStack transition? – nwales Jul 10 '17 at 19:25
  • figured it out: import CardStackStyleInterpolator from 'react-navigation/src/views/CardStackStyleInterpolator' and then default: CardStackStyleInterpolator.forHorizontal(sceneProps) – nwales Jul 10 '17 at 19:43
  • @TimRijavec is it possible to configure back button animations, as well? – Julian K Aug 04 '17 at 10:39
  • @TimRijavec Thanks for this amazing solution. Is there a way to switch back to default stack navigator transition if transition config is not passed via route.params? Thanks in anticipation. – shet_tayyy Oct 10 '17 at 14:31
  • 1
    @JulianK You configure back animation through the three-way interpolation in MyTransition. You can see I'm using an array of 3 indices [index - 1, index, index + 1], where index represents current page index and interpolates between previous and next page index. – Tim Rijavec Oct 10 '17 at 14:49
  • @rash.tay I would copy the default and put it as a fallback if an unknown transition is passed through. You can find them in react-navigation views/CardStack/TransitionConfigs file. – Tim Rijavec Oct 10 '17 at 14:52
  • @TimRijavec I have done that already. I thought it could be done in a better way. Anyways, thanks a lot for such a wonderful solution, Tim – shet_tayyy Oct 10 '17 at 14:54
  • @TimRijavec : i am solving the same issue but still with your answer i couldnt. may be i am making mistake. can u tell me where did u define myCustomTransition animation? where you called the navigate or where u define transitionconfiguration ? – djk Nov 27 '17 at 16:45
  • @djk I'm defining all custom transitions in a separate transitions.js config file and then just importing it when configuring the navigator – Tim Rijavec Nov 27 '17 at 17:34
  • 1
    @TimRijavec Any idea how to pass transitionSpec when using transitions for different screens? – Turnip Jan 31 '18 at 22:09
  • There is no `scene` in the `sceneProps` anymore (currently at v5), so this solution doesn't work anymore – mgPePe Jun 02 '20 at 10:41