krissanawat

React native Developer ,Coffee addict

React Native Apple App of the Day Animation Part II : Open Image

In this post, we are going to continue from where we left off in our last part of the React Native apple app of the day. In part one of this tutorial part, we successfully implemented the React Native Shared element transition and set up the UI part. Here, we are going to put more effort into animation. We want to make the image transition and selection animation cool.this tutorial inspired from React native ecommerce template from instamobile
React Native doest support shared element transition by default. For this tutorial, the idea is to replicate the images and display them on top of a target element by using some cool animation. This part of the tutorial will provide us with really cool and interesting insights on using animations in React Native.
So, let us begin!!

Initializing Variables

First of all, we need to initialize some variables so as to store the old position of the images as well as provide the new position. In order to do that, we need to make use of the Animated component provided by the react-native package. Here, initialize three variables oldPosition, position and dimensions as shown in the code snippet below:
this.oldPosition = {}; // for keep old element coordinate 
this.position = new Animated.ValueXY(); // use for setup animation in position 
this.dimensions = new Animated.ValueXY(); // use for setup animation in size
As shown in the code snippet above:
oldPosition
  to store the old element co-ordinate.
position
 is initialized to ValueXY method of Animated component for the position.
dimensionsis
initialized to ValueXY method of Animated component for the size.

Creating a function to open the Image

In this step, we are going to define a function named openImage that receives an image index as a parameter and configures the old position and size as well as the new position. The function with the code to configure the position and size of the index image is provided in the code snippet below:
openImage = index => { 
this.allImages[index].measure((x, y, width, height, pageX, pageY) => { 
    this.oldPosition.x = pageX; 
    this.oldPosition.Y = pageY; 
    this.oldPosition.width = width; 
    this.oldPosition.height = height; 

    this.position.setValue({ x: pageX, y: pageY, }); 
    this.dimensions.setValue({ x: width, y: height, }); 
});
In the code snippet above, we identify the image object by using index value. Then, by using the Measure method, we get the image coordinate and set them to the current coordinate. When we want to bring the image back to the old location, we use oldPosition variable.
Then, we need to bind the function openImage to onPress event of TouchableWithoutFeedback component as shown in the code snippet below:
<TouchableWithoutFeedback key={image.id} onPress={() => this.openImage(index)}>

Implementing Overlay

Now, we are going to create an overlay of copy image over the selected image. In order to do that, we need to place a View component with a copy of the original image after the ScrollView component in our App.js file.
First, let us create a View with style binding of absoluteFillObjectas shown in the code snippet below:
</ScrollView> 
  <View style={StyleSheet.absoluteFillObject}</View>
Hence, we get the following result in our emulator screen:
As we can see in the code snippet above, the new View will block all views and we cannot do anything.
To solve that problem, we are going to use activeImage state to toggle the pointerEventsprop to auto or none as shown in the code snippet below:
<View style={StyleSheet.absoluteFillObject} pointerEvents={this.state.activeImage ? 'auto' : 'none'}>
Hence, we get the following result in our emulator screen:
But as we can see in the emulator simulation above, we are not able to scroll the screen when we click or touch on the image.

Configuring Overlay

Next, we are going to add two View components with flex style to contain the image and the text as shown in the code snippet below:
<View style={{flex: 2}}></View>
<View style={{flex: 1}}></View>
Then, we are going to add the Animated.Image component to the first View component as shown in the code snippet below:
<View style={{flex: 2}} ref={view => (this.viewImage = view)}>
   <Animated.Image 
      source={ this.state.activeImage ? this.state.activeImage.src : null } 
      style={[ { resizeMode: 'cover', top: 0, left: 0, height: null, width: null, }, ]}
    ></Animated.Image> 
</View>
 
<View style={{flex: 1}}></View>
In the code snippet above, we are assigning the source to Image component based on activeImage state. If true, we assign a source of the image to Image component. Then, we bind the styles to stick the replicated image on top of the screen.
Now, we need to add animation style to the Animated Image component. For that, we define a constant named activeImageStyle with size configurations as shown in the code snippet below:
render() { 
 const activeImageStyle = { 
   width: this.dimensions.x, 
   height: this.dimensions.y, 
   left: this.position.x, 
   top: this.position.y, 
  };
Then, we need to attach the activeImageStyle to the style prop array of the Animated Image component as shown in the code snippet below:
<Animated.Image 
  source={ this.state.activeImage ? this.state.activeImage.src : null } 
  style={[ { resizeMode: 'cover', top: 0, left: 0, height: null, width: null, },
  activeImageStyle, 
  ]}>
</Animated.Image>
Therefore, we get the following result in our emulator screen:
As we can see in the emulator simulation above, the corners of the screen will change and the border will appear as we click on the image.
But, the replicated image does not enlarge as a cover, over the screen.
In order to solve this issue, first, we need to get the reference to the parent View component by using ref prop as shown in the code snippet below:
we gating parent View object by add ref
<View style={{flex: 2}} 
 ref={view => (this.viewImage = view)}> 
    <Animated.Image >
Now, we are able to get the size of the parent View . As a result, we can now enlarge the image to fit the screen. We are going to do that by activating the animation when the image enlarges.

Activating animation

In order to activate animation, we need to go back to openImage function. Then, we need to set the current image index to state. After that, we can use the callback to trigger the animation. The code to implement this is provided in the code snippet below:
this.setState({activeImage: images[index]}, () => { 
       this.viewImage.measure((dx, dy, dWidth, dHeight, dPageX, dPageY) => { 
          Animated.parallel([ 
             Animated.timing(
               this.position.x, 
               { toValue: dPageX, duration: 300, }
             ),
             Animated.timing(
               this.position.y, 
               { toValue: dPageY, duration: 300, }
             ), 
             Animated.timing(
               this.dimensions.x, 
               { toValue: dWidth, duration: 300, }
             ), 
             Animated.timing(
               this.dimensions.y, 
               { toValue: dHeight, duration: 300, }
             ), 
          ]).start(); 
        }); 
}
Here, we measure viewImage variable that contains the parent View data. Then, we create the animation with timing function provided by Animated component which makes the enlarging Image size equal to the parent View.
Therefore, the final result is provided in the emulator simulation below:
Hence, we have successfully implemented the enlarging animation when we click on any image on the screen.

Conclusion

In this second part of our tutorial, we continued from where we left off at part one. So, it is suggested to go through the first part in order to get the full insight. Here, we learned how to bootstrap animation in the React Native app. We also got detail guidance on how to collect the element coordinates data by using Measure method. This part also helped us know how to use multiple animations at the same time. In the next part, we will learn how to hide an element and display the text section.

Credit

And the image is acquired from Unsplash.

Disclosure

This post includes affiliate links; I may receive compensation if you purchase
products or services from the different links provided in this article.

Tags

More by krissanawat

Topics of interest