Skip to content

Instantly share code, notes, and snippets.

@portons
Created January 30, 2019 06:33
Show Gist options
  • Select an option

  • Save portons/ee2c0fa02e6e07593a6b6c6e053b99c8 to your computer and use it in GitHub Desktop.

Select an option

Save portons/ee2c0fa02e6e07593a6b6c6e053b99c8 to your computer and use it in GitHub Desktop.
Shared transition example
# Lets say we've got Screen A and Screen B, and we want to make a shared transition from A to B.
# We first create a 'manager', or a 'service', call it however you like :) It's a simple class:
class SomeAnimationManager {
constructor(navigation) {
// We pass the navigation bc we'd want to create transitions from the manager,
// as it's also the one responsible for the animations
this.navigation = navigation;
// This is going to be a reference to the original element we're 'sharing'
this.originalElementRef = null;
// Here we're going to save the original element dimensions, to be used
// as the 'starting point' in screen B
this.initialDimensions = null;
// This is an example of an animated value we're going to pass to the shared element in screen B
this.translateY = null;
}
// Here we set the original element ref
setOriginalElementRef = (ref) => this.originalElementRef = ref;
// This is the function that would be called when we want to navigate
beginTransition = () => {
this.originalElementRef.measureInWindow((x, y, width, height) => {
this.initialDimensions = { x, y, width, height };
// Now that we have the initial dimensions, we can navigate to screen B, and pass it
// the reference to this animation manager
this.navigation.push('B', { animationManager: this });
})
};
// This method is called from Screen B, before it mounts. Here we ALREADY have the initial dimensions,
// needed for the transition.
getInitialAnimationValues = () => {
const { y } = this.initialDimensions;
// Now, our initial animated value is the position of the shared element on screen A,
// and we pass it to screen B
this.translateY = new Animated.Value(y);
return {
transform: [{ translateY: this.translateY }]
}
}
// Called from screen B, and changes the values of the animation you want to perform.
// This object is the one we passed to screen B, and when changing this.translateY, shared element will animate accordingly
// because its style has a reference to this Animated object.
animateIntro = () => {
Animated.timing(
this.translateY,
{ toValue: 0 }
).start();
}
}
-------------
# This is screen A, a very simplified version of it, with a SharedElemenet:
class ScreenA extends React.Component {
constructor() {
// Here we assign the animation manager in Screen A
this.animationManager = new SomeAnimationManager(this.props.navigation);
}
render() {
<View>
// Here we set the reference to the original element, inside the animation manager
<SharedElement ref={this.animationManager.setOriginalElementRef}/>
</View>
}
}
---------------
# Screen B, which takes everything it needs from the manager:
class ScreenB extends React.Component {
constructor() {
// Here we get the reference to the animation manager which we passed FROM the animation
// manager, and it's the same one used in Screen A
this.animationManager = this.props.navigation.getParam('animationManager');
// This method will init all of the animations needed for the transition
this.initAnimatedValues();
}
initAnimatedValues = () => {
// We get the style object for our shared element, and the manager's going to
// be responsible for its animation
this.animatedStyle = this.animationManager.getInitialAnimationValues();
};
// When Screen B is mounted, it already has the initial animated style with initial values from A.
// And now we tell the animation manager to actually animate.
componentDidMount() {
this.animationManager.animateIntro();
}
render() {
return (
<SharedElement style={this.animatedStyle}/>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment