DEV Community

Ajmal Hasan
Ajmal Hasan

Posted on

3

React Native Shared Elements Using Reanimated 3

Shared element transitions in React Native involve smoothly transitioning the position, size, and appearance of elements between two screens. This is often used for a seamless user experience when navigating between screens.

Prerequisite:

Install and configure by following below links:

  1. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#installation
  2. https://reactnavigation.org/docs/getting-started/#wrapping-your-app-in-navigationcontainer
  3. https://reactnavigation.org/docs/hello-react-navigation#installing-the-native-stack-navigator-library
  4. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/#installation

After doing above step lets move to coding. I have added inline comments for understating.

RenderItem.js (flatlist render item)

import {Pressable, StyleSheet, Text, View} from 'react-native';
import React from 'react';
import {useNavigation} from '@react-navigation/native';
import Animated, {FadeInDown} from 'react-native-reanimated';

const RenderItem = ({item, index}) => {
  const navigation = useNavigation();
  return (
    // Animated.View for fading in the item with delay based on index
    <Animated.View entering={FadeInDown.delay(200 * index)}>
      <Pressable
        style={styles.container}
        onPress={() => {
          navigation.navigate('Details', {item: item});
        }}>
        {/* Animated.Image with sharedTransitionTag is used to create a visually appealing shared element transition between screens when navigating, ensuring a smooth animation of the image as it moves from one screen to another. */}
        <Animated.Image
          source={item.image}
          style={styles.image}
          sharedTransitionTag={item.name}
        />
        <View style={styles.textContainer}>
          <Text style={styles.textName}>{item.name}</Text>
          <Text style={styles.textLocation}>{item.location}</Text>
        </View>
      </Pressable>
    </Animated.View>
  );
};

export default RenderItem;

Enter fullscreen mode Exit fullscreen mode

Detail Screen

import {StyleSheet, Text, View, useWindowDimensions} from 'react-native';
import React from 'react';
import Animated, {FadeIn, FadeInDown} from 'react-native-reanimated';
import Header from '../components/Header';
import Button from '../components/Button';
import LinearGradient from 'react-native-linear-gradient';

const Detail = ({route}) => {
  const {item} = route.params;
  const {width} = useWindowDimensions();

  return (
    <LinearGradient colors={['#a8ff78', '#78ffd6']} style={styles.container}>
      <Header />
      <View>
        <View>
          <Animated.Image
            sharedTransitionTag={item.name}
            source={item.image}
            style={{width: width, height: width}}
          />
          <Animated.View
            style={styles.textContainer}
            entering={FadeIn.delay(600)}>
            <Text style={styles.textName}>{item.name}</Text>
            <Text style={styles.textLocation}>{item.location}</Text>
          </Animated.View>
        </View>
        <Animated.View entering={FadeInDown.delay(800)}>
          <Text style={styles.textAbout}>About</Text>
          <Text style={styles.text}>{item.about}</Text>
        </Animated.View>
      </View>
      <Button />
    </LinearGradient>
  );
};

export default Detail;
Enter fullscreen mode Exit fullscreen mode

Header of Detail Screen

/* eslint-disable react-native/no-inline-styles */
import {Image, Platform, Pressable, StyleSheet} from 'react-native';
import React from 'react';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import Animated, {FadeIn} from 'react-native-reanimated';
import {useNavigation} from '@react-navigation/native';

const Header = () => {
  const inset = useSafeAreaInsets();
  const navigation = useNavigation();
  return (
    <Animated.View
      style={[styles.container, {top: Platform.OS === 'ios' ? inset.top : 20}]}
      entering={FadeIn.delay(400)}>
      <Pressable
        onPress={() => {
          navigation.goBack();
        }}>
        <Image
          source={require('../assets/chevron.png')}
          style={styles.chevron}
        />
      </Pressable>
      <Pressable
        onPress={() => {
          console.log('LIKE');
        }}>
        <Image source={require('../assets/like.png')} style={styles.chevron} />
      </Pressable>
    </Animated.View>
  );
};

export default Header;

Enter fullscreen mode Exit fullscreen mode

Bottom Button on detail screen

import {Pressable, StyleSheet, Text, useWindowDimensions} from 'react-native';
import React from 'react';
import Animated, {FadeInDown} from 'react-native-reanimated';

const Button = () => {
  const {width} = useWindowDimensions();

  // Creating an Animated Pressable component using createAnimatedComponent //ALTERNATE:==> <Animated.View/>
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

  return (
    <AnimatedPressable
      style={[styles.container, {width: width * 0.9}]} // Styles for the Pressable
      entering={FadeInDown.delay(1000)} // FadeInDown animation with a delay of 1000 milliseconds
      onPress={() => {
        console.log('BOOKING NOW');
      }}>
      <Text style={styles.text}>Booking Now</Text>
    </AnimatedPressable>
  );
};
export default Button;

Enter fullscreen mode Exit fullscreen mode

GITHUB REPO:

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more