react-nativereact-native-flatlistreact-native-swiperreact-native-deck-swiper

how to implement the image rotary using flatlist in react native?


I'm trying to accomplish the vertical carousel as shown in the below gif. I'm struck by the second screen, where when the user scrolls the data from bottom to top or vice versa both the content and image change, how to achieve this? looking forward to your help?enter image description here


Solution

  • I have included a snack example which is mostly similar to what you want. You can use reanimated, Flatlist achieve the animation:

    Snack Link

    Code:

    import * as React from 'react';
    import { Text, View, StyleSheet, FlatList, Dimensions } from 'react-native';
    import Constants from 'expo-constants';
    import Animated, {
      useSharedValue,
      useAnimatedScrollHandler,
      useAnimatedStyle,
      interpolate,
      Extrapolate,
    } from 'react-native-reanimated';
    const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
    
    const { width, height } = Dimensions.get('window');
    
    const bottomHeight = height - 150 - 30 - Constants.statusBarHeight;
    
    const data = [
      {
        title: 'data1',
        image:
          'https://assets.website-files.com/5f204aba8e0f187e7fb85a87/5f210a533185e7434d9efcab_hero%20img.jpg',
      },
      {
        title: 'data2',
        image:
          'https://www.whoa.in/201604-Whoa/10-alone-broken-image-mobile-wallpaper-hd-image.jpg',
      },
      {
        title: 'data3',
        image:
          'https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
      },
      {
        title: 'data4',
        image:
          'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTntlma5HASL0HAM-KiC01A-JX4MxKousAA6A&usqp=CAU',
      },
    ];
    
    
    const ImageContent = ({ image, scrollValue, index }) => {
    
      const animatedStyle = useAnimatedStyle(() => {
        const inputRange = [index * bottomHeight, (index + 1) * bottomHeight];
        const translateY = interpolate(
          scrollValue.value,
          inputRange,
          [0, -150],
          Extrapolate.CLAMP
        );
        return {
          transform: [{ translateY }],
        };
      });
      return (
        <Animated.Image
          source={{ uri: image }}
          style={[styles.image, { zIndex: data.length - index }, animatedStyle]}
          resizeMode="cover"
        />
      );
    };
    
    const TopPart = React.memo(({ scrollValue }) => {
      return (
        <View style={styles.topPartContainer}>
          {data.map(({ image }, index) => (
            <ImageContent {...{ scrollValue, image, index }} />
          ))}
        </View>
      );
    });
    
    const Item = ({ item, index }) => {
      return (
        <View
          style={[
            styles.item,
          ]}>
          <Text style={{ color: 'red' }}>{item.title}</Text>
        </View>
      );
    };
    
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        paddingTop: Constants.statusBarHeight,
        backgroundColor: '#ecf0f1',
      },
      topPartContainer: {
        width: 150,
        height: 150,
        borderRadius: 75,
        alignSelf: 'center',
        overflow: 'hidden',
      },
      image: {
        ...StyleSheet.absoluteFillObject,
        backgroundColor: '#fff',
        borderRadius: 75,
      },
      item: {
        width,
        backgroundColor: '#fff',
        justifyContent: 'center',
        alignItems: 'center',
        height: bottomHeight,
      },
    });
    
    function App() {
      const scrollValue = useSharedValue(0);
    
      const handler = useAnimatedScrollHandler((event) => {
        scrollValue.value = event.contentOffset.y;
      });
      return (
        <View style={styles.container}>
          <TopPart {...{ scrollValue }} />
          <View style={{ flex: 1, paddingTop: 30, height: bottomHeight }}>
            <AnimatedFlatList
              contentContainerStyle={{ height: data.length * bottomHeight }}
              showsVerticalScrollIndicator={false}
              onScroll={handler}
              scrollEventThrottle={16}
              data={data}
              pagingEnabled
              keyExtractor={(item) => item.title}
              renderItem={({ item, index }) => <Item {...{ item, index }} />}
            />
          </View>
        </View>
      );
    }