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

637 Views Asked by At

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

1

There are 1 best solutions below

2
Ashwith Saldanha On BEST ANSWER

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>
  );
}