Shared Element Transition
Android and iOS both support shared element transitions, where you can smoothly animate 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
On Android, 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>
On Android, 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. On Android, try the 'elevationScale' or 'hold' transitions on the the outgoing scene.
<Scene stateKey="inbox" crumbStyle={{type: 'elevationScale'}}><Inbox /></Scene>
Opening Sheets on iOS
Fluid shared transitions also work when opening sheets on iOS. You specify the name in the 'sharedElement' prop of the Sheet
. You don't need to wrap the target view in a SharedElement
because iOS fluid transitions target the whole sheet. In our email example, when a user taps a sender's icon we bring up their details in a sheet. We wrap the icon in a SharedElement
so that iOS zooms the sheet out from the sender button.
<Button onPress={() => setDetent('expanded')}>
<SharedElement name="sender">
<Image />
</SharedElement>
</Button>
<Sheet sharedElement="sender" detent={detent}>
</Sheet>