DEV Community

Cover image for Creating a Smooth Animated Vertical List in React Native with Reanimated
Amit Kumar
Amit Kumar

Posted on

1 1 1 1 1

Creating a Smooth Animated Vertical List in React Native with Reanimated

When it comes to mobile UI, animations can elevate the user experience, making interactions feel more fluid and engaging. In this blog, we’ll build an animated vertical list using react-native-reanimated that creates a smooth scrolling effect with opacity and scaling transitions.


Image description


Prerequisites

Before we start, ensure you have the following installed in your React Native project:

npm install react-native-reanimated react-native-gesture-handler
Enter fullscreen mode Exit fullscreen mode

Also, update your babel.config.js file to enable Reanimated’s plugin:

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'],
};
Enter fullscreen mode Exit fullscreen mode

Building the Animated Vertical List

1. Import Required Dependencies

We begin by importing essential components from react-native and react-native-reanimated:

import { Dimensions, Image, StyleSheet, Text, View } from 'react-native';
import React from 'react';
import Animated, {
  interpolate,
  useAnimatedScrollHandler,
  useAnimatedStyle,
  useSharedValue,
} from 'react-native-reanimated';
Enter fullscreen mode Exit fullscreen mode

2. Define the Vertical List Component

const VerticalList = ({ data = [] }) => {
  const { height } = Dimensions.get('screen');
  const spacing = 8;
  const itemSize = height * 0.72;
  const itemFullSize = itemSize + spacing * 2;
  const scrollY = useSharedValue(0);

  const onScroll = useAnimatedScrollHandler(event => {
    scrollY.value = event.contentOffset.y / itemFullSize;
  });
Enter fullscreen mode Exit fullscreen mode

We define the item size relative to the screen height and calculate spacing accordingly.

3. Create the Animated Card Component

Each item in our list will have an animated opacity and scale effect based on its position in the list.



export const DATA = [
  {
    id: 'V_ID_1',
    title: 'Iron Man',
    thumbnailUrl:
      'https://ew.com/thmb/OEm1NLRTUG5HuHswbWLjvLJ5GIg=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc():format(webp)/iron-man-2000-c36c45429d5148e5a5871a887cc3d96c.jpg',
    duration: '8:18',
    uploadTime: 'May 9, 2011',
    views: '24,969,123',
    author: 'Vlc Media Player',
    videoUrl:
      'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
    audioUrl:
      'https://github.com/rafaelreis-hotmart/Audio-Sample-files/raw/master/sample.mp3',
    description:
      'A thrilling superhero movie following Tony Stark, a billionaire genius who becomes Iron Man after creating a powerful armored suit to fight injustice.',
    subscriber: '25,254,545 Subscribers',
    isLive: true,
  },
// rest data
]


const AnimationCard = ({ item, index, scrollY }) => {
    const animatedStyle = useAnimatedStyle(() => {
      return {
        opacity: interpolate(scrollY.value, [index - 1, index, index + 1], [0.3, 1, 0.3]),
        transform: [
          {
            scale: interpolate(scrollY.value, [index - 1, index, index + 1], [0.92, 1, 0.92]),
          },
        ],
      };
    });

    return (
      <Animated.View style={[styles.card, animatedStyle]}>
        <Image source={{ uri: item.thumbnailUrl }} style={styles.backgroundImage} blurRadius={50} />
        <Image source={{ uri: item.thumbnailUrl }} style={styles.thumbnail} resizeMode="cover" />
        <View style={styles.textContainer}>
          <Text style={styles.title}>{item.title}</Text>
          <Text style={styles.description} numberOfLines={3}>{item.description}</Text>
        </View>
        <View style={styles.authorContainer}>
          <Image source={{ uri: item.author.avatar }} style={styles.avatar} />
          <Text style={styles.authorName}>{item.author.name}</Text>
        </View>
      </Animated.View>
    );
  };
Enter fullscreen mode Exit fullscreen mode

4. Render the Animated List

const renderItem = ({ item, index }) => <AnimationCard item={item} index={index} scrollY={scrollY} />;

  return (
    <Animated.FlatList
      data={data}
      renderItem={renderItem}
      contentContainerStyle={styles.listContainer}
      snapToInterval={itemFullSize}
      decelerationRate={'fast'}
      onScroll={onScroll}
      scrollEventThrottle={16}
    />
  );
};
Enter fullscreen mode Exit fullscreen mode

5. Define the Styles

To keep our component clean, let’s define a StyleSheet:

const styles = StyleSheet.create({
  card: {
    flex: 1,
    height: Dimensions.get('screen').height * 0.72,
    padding: 16,
    borderRadius: 8,
    gap: 8,
  },
  backgroundImage: {
    ...StyleSheet.absoluteFillObject,
    borderRadius: 12,
  },
  thumbnail: {
    flex: 1,
    height: Dimensions.get('screen').height * 0.4,
  },
  textContainer: {
    gap: 8,
  },
  title: {
    fontSize: 24,
    fontWeight: '700',
    color: '#fff',
  },
  description: {
    color: '#ddd',
  },
  authorContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  avatar: {
    width: 24,
    aspectRatio: 1,
    borderRadius: 12,
  },
  authorName: {
    fontSize: 12,
    color: '#ddd',
  },
  listContainer: {
    paddingHorizontal: 24,
    paddingVertical: (Dimensions.get('screen').height - Dimensions.get('screen').height * 0.72) / 2,
    gap: 16,
  },
});
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

By using Reanimated’s useSharedValue, useAnimatedScrollHandler, and useAnimatedStyle, we’ve created a beautiful and responsive animated vertical list. This technique makes the UI more engaging and can be used for displaying articles, media content, or product listings.

Let me know in the comments if you have any questions or enhancements! 🚀

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo 📊✨

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay