React native Apple App of the day Animation #2 : 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.
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 toValueXY
method of Animated component for the position.dimensions
is initialized toValueXY
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 absoluteFillObject
as 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 pointerEvents
prop 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
The content is acquired from the #2 Apple App of the day Animation by Unsureprogrammer.
Disclosure
This post includes affiliate links; I may receive compensation if you purchase
products or services from the different links provided in this article.
And the image is acquired from Unsplash.
Originally published at Kriss.