Created
January 30, 2019 06:33
-
-
Save portons/ee2c0fa02e6e07593a6b6c6e053b99c8 to your computer and use it in GitHub Desktop.
Revisions
-
Vladimir Porton created this gist
Jan 30, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,110 @@ # 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}/> ) } }