React Navigation bindings for react-native-shared-element π«
Supported by latest stable version (2.x):
- react-navigation 4 & 3
- react-navigation-stack 2
- react-navigation-stack 1 (use react-navigation-shared-element@1)
V3 prerelease (supports both react-navigation API 4.x and 5.x from a single codebase)
- react-navigation 5
- react-navigation 4 & 3
- react-navigation-stack 2
Unlikely to be supported:
Open a Terminal in your project's folder and run,
$ yarn add react-navigation-shared-element react-native-shared-element
Enure that react-native-shared-element is also linked into your project.
Finally, make sure that the compatible react-navigation dependencies are installed:
$ yarn add react-navigation@4 react-navigation-stack@2
react-navigation@5 is not supported yet, so don't bother..
In order to enable shared element transitions, the following steps need to be performed
- Create a stack-navigator using
createSharedElementStackNavigator
- Wrap your component with
<SharedElement>
and provide a uniqueid
- Define a static
sharedElements
config on the Screen that you want to animate
import { createSharedElementStackNavigator } from 'react-navigation-shared-element';
const stackNavigator = createSharedElementStackNavigator(
{
List: ListScreen,
Detail: DetailScreen,
},
{
initialRouteName: 'List',
}
);
const AppContainer = createAppContainer(stackNavigator);
// ListScreen.js
import { SharedElement } from 'react-navigation-shared-element';
class ListScreen extends React.Component {
renderItem(item) {
const { navigation } = this.props;
return (
<TouchableOpacity onPress={() => navigation.push('Detail', { item })}>
<SharedElement id={`item.${item.id}.photo`}>
<Image source={item.photoUrl} />
</SharedElement>
</TouchableOpacity>
);
}
}
// DetailScreen.js
const DetailScreen = (props) => {
const item = props.navigation.getParam('item');
return (
<SharedElement id={`item.${item.id}.photo`}>
<Image source={item.photoUrl} />
</SharedElement>
);
};
DetailScreen.sharedElements = (navigation, otherNavigation, showing) => {
const item = navigation.getParam('item');
return [`item.${item.id}.photo`];
};
The createSharedElementStackNavigator
function wraps an existing stack-navigator and enables shared element transitions for it.
It performs the following actions
- Creates a top-level renderer to host the shared element transitions
- Wraps each route with a shared element scene
- Detect route changes and trigger shared element transitions
Arguments
Argument | Type | Description |
---|---|---|
routeConfig |
object |
Routes-config |
stackConfig |
object |
Optional stack navigator config |
sharedElementConfig |
object |
Optional shared element config |
When transitions aren't working as expected, you can enable debug-mode to log scene transitions and shared-element id's to the console. The log output is useful for understanding scene changes and for reporting issues.
const stackNavigator1 = createSharedElementStackNavigator(
{ ... }, // routeConfig
{ ... } // stackConfig
{
name: 'MyStackNav',
debug: true
}
);
The <SharedElement>
component accepts a single child and a "shared" id. The child is the element that is made available for doing shared element transitions. It can be any component, like a <View>
, <Text>
or <Image>
. In case the wrapped view is an <Image>
, special handling is performed to deal with image loading and resizing.
This component is synonymous for the <SharedElement>
component as defined in react-native-shared-element
. Instead of a node
it uses an id
to create a higher lever API which automatically ties in with the scenes created by createSharedElementStackNavigator
.
Props
Property | Type | Description |
---|---|---|
children |
element |
A single child component, which must map to a real view in the native view hierarchy |
id |
string |
Unique id of the shared element |
View props... |
Other props supported by View |
In order to trigger shared element transitions between screens, a static sharedElements
config needs to be defined on one of the two screens. For
each screen transition, both screens are evaluated and checked whether they have a sharedElements
config. The screen that is being shown is evaluated first, followed by the screen that is being hidden. If undefined
is returned, evaluation continues at the other screen.
The sharedElements
function receives 3 arguments
Argument | Type | Description |
---|---|---|
navigation |
NavigationProp |
Navigation prop of the current screen. You can use this to get the params of the screen using getParam , or the route-name using state.routeName |
otherNavigation |
NavigationProp |
The navigation-prop of the other screen. You can use this to get the params of that screen using getParam , or the route-name using state.routeName |
showing |
boolean |
true when this screen is being shown, and false when this screen is being hidden. |
The return value should be either undefined
or an array of shared-element configs or identifiers. Specifying a string-identifier is shorthand for {id: 'myid'}
.
Basic example
class DetailScreen extends Component {
static sharedElements = (navigation, otherNavigation, showing) => {
// Transition element `item.${item.id}.photo` when either
// showing or hiding this screen (coming from any route)
const item = navigation.getParam('item');
return [`item.${item.id}.photo`];
}
render() {...}
}
Only transition when coming from a specific route
If you only want to show a transition when pushing from a particular screen, then use the route-name and showing
argument.
class DetailScreen extends Component {
static sharedElements = (navigation, otherNavigation, showing) => {
if ((otherNavigation.state.routeName === 'List') && showing) {
const item = navigation.getParam('item');
return [`item.${item.id}.photo`];
}
}
...
}
Customize the animation
If the source- and target elements are visually distinct, the consider using a cross-fade animation.
class DetailScreen extends Component {
static sharedElements = (navigation, otherNavigation, showing) => {
const item = navigation.getParam('item');
return [{
id: `item.${item.id}.photo`,
animation: 'fade'
// resize: 'clip'
// align: ''left-top'
}];
}
...
}
The following fields can be specified in a config item
Field | Type | Description |
---|---|---|
id |
string |
Id that corresponds to the id specified in the <SharedElement> component |
otherId |
string |
Optional id that corresponds to the id specified in the other screen. |
animation |
move | fade |
Type of animation to perform (default = move ), see SharedElementAnimation |
resize |
auto | stretch | clip | none |
Resize behavior of the transition (default = auto ), see SharedElementResize |
align |
auto | top-left | ... |
Align behavior of the transition (default = auto ), see SharedElementAlign |
- Snapchat Shared Transitions - βCan it be done in React Native?β (with react-navigation v5)
- Airbnb Shared Transition - βCan it be done in React Native?β (with react-navigation v4)
React navigation shared element library is licensed under The MIT License.