Shared Element Transition (Android)

Android supports shared element transitions, where you can smoothly animate changes between related Views across two scenes. The Navigation router exposes this functionality to React using the SharedElement component. To identify a pair of shareable elements, you wrap each one in a SharedElement component and give them both the same name.

Note

Shared element transitions disable the predictive back gesture

In our email example app, we smooth out the transition when a user opens an email by visually connecting the subject line on the 'inbox' scene with the open email on the 'mail' scene. We wrap the views on each scene inside a SharedElement component and give them both the same name.

// The 'inbox' scene
<Pressable
  onPress={() => {
    stateNavigator.navigate('mail', {id: id});
  }}>
  <SharedElement name={'email' + id}>
    <Text>Meeting invite</Text>
  </SharedElement>
</Pressable>
// The 'mail' scene
<SharedElement name={'email' + id}>
  <Text>Meeting invite</Text>
  <Text>Please come along to find out more about...</Text>
</SharedElement>

When you navigate between two States, the Navigation router calls the function you assign to the sharedElements prop of the destination Scene component. You return the shared name of the views that will participate in the transition. Return an array of names if sharing multiple elements. In our email example, we return the name we gave to the selected email.

<Scene stateKey="mail" sharedElements={data => 'email' + data.id}><Mail /></Scene>

There's an untidy overlap as the outgoing subject line turns into the incoming email. We neaten it up by setting the fadeMode prop to 'through'. This fades out the subject and fades in the email. We apply the prop to both SharedElement components so that the fade reverses when the user returns to their inbox.

<SharedElement name={'email' + id} fadeMode="through">

Not all custom animations work with shared element transitions. Try the 'elevationScale' or 'hold' transitions on the the outgoing scene.

<Scene stateKey="inbox" unmountStyle={{type: 'elevationScale'}}><Inbox /></Scene>