react native reanimated three items but one bigger as the neighbor

Viewed 32

I want to make a flatlist with three items and the selected/current Index item should be bigger as the two items next to.

enter image description here

Current Code:

  const translateX = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (e) => {
      translateX.value = e.contentOffset.x;
    }
  })

  const animatedStyle = useAnimatedStyle(() => {
    const scale = interpolate(translateX.value, [width / 3, 0, width / 3], [0.2, 1, 0.2], Extrapolate.CLAMP);
    return {
      transform: [{
        scale
      }]
    }
  }, []);

  const renderI = ({ item }) => (
    <Animated.View style={[animatedStyle]}>
      <ProductCardAuto
        {...item}
        onPressProduct={() => handleNavigateToProduct(item)}
        onPressReviews={handleOpenModalReviews}
      />
    </Animated.View>
  )

    <Animated.FlatList
        data={mockProducts}
        renderItem={renderI}
        keyExtractor={(item) => item.id}
        snapToAlignment="start"
        decelerationRate={"normal"}
        onScroll={scrollHandler}
        horizontal
        snapToInterval={120}
    />

I am very thankful for your help. Idk what I am doing wrong. Maybe you can tell me what is wrong with it. it does not work its scale all items to 0.2 if I scroll

2 Answers

kindof tried to make it acc to what you needed.

You can check this expo : https://snack.expo.dev/d_myr1HdyN

import React,{useState,useEffect,useRef,useCallback} from 'react';
import { Text, View, StyleSheet ,Animated,FlatList,Dimensions,Easing } from 'react-native';
import Constants from 'expo-constants';

// You can import from local files
import AssetExample from './components/AssetExample';

// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';

const data = ["hey there","indian","mango","whatsup","arsenal","jojoba"]

const screenWidth = Dimensions.get("window").width;


const EachItem = (props) => {
  const {text = "",index=0,currentView={}} = props || {}

  const {visible = false, index:visibleIndex = 0} = currentView;

  console.log(visible,visibleIndex,"wuhyyyyy")

  const animRef = useRef(new Animated.Value(0)).current

  const startAnimation = useCallback(() => {
    Animated.timing(animRef,{
      toValue:1,
      duration:1000,
      useNativeDriver:true,
      easing:Easing.ease,
    }).start()
  },[animRef])

    const stopAnim = useCallback(() => {
    Animated.timing(animRef,{
      toValue:0,
      duration:1000,
      useNativeDriver:true,
      easing:Easing.ease,
    }).start()
  },[animRef])

  useEffect(() => {
    if(visible === true && visibleIndex===index ){
startAnimation()
    }

    if(visible === false  ){
  setTimeout(() =>stopAnim(),1000)
    }

  },[startAnimation,visible,visibleIndex,index,stopAnim])

  const scaleInter = animRef.interpolate({inputRange:[0,1],outputRange:[1,1.5]})

  return(
    <Animated.View style={{marginHorizontal:20 ,height:100,
    backgroundColor:'rgba(102,116,255,0.6)',
    width:screenWidth/3,
    alignItems:'center',
    justifyContent:'center',
    transform:[{
      scale:scaleInter
    }]
    }}  >
   
    <Text>{text}</Text>
  
    </Animated.View>
  )
}

export default function App() {

  const [currentView,setCurrentView] = useState({visible:false,index:null})
  

  const onViewRef = React.useRef((viewableItems) => {
    console.log(viewableItems?.viewableItems,"viewableItems")

  if(viewableItems?.viewableItems.length === 2){
    setCurrentView({visible:false,index:null})
  }

  if(viewableItems?.viewableItems.length === 1){
    const currentItemIndex = viewableItems?.viewableItems[0]?.index
     setCurrentView({visible:true,index:currentItemIndex})
  }

  });

  const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 30 });

  const eachItem = ({item,index}) => {
    return <EachItem text={item} currentView={currentView} index={index} />
  }

  return (
    <View style={styles.container}>
     <Animated.FlatList 
     data={data}
     style={{flex:1}}
     contentContainerStyle={{paddingTop:100}}
     horizontal={true}
     onViewableItemsChanged={onViewRef.current}
        viewabilityConfig={viewConfigRef.current}
        renderItem={eachItem}
     />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    // justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
    // alignItems:'center'
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

Hope it helps. feel free for doubtsenter image description here

Even if the question has been already answered, I would suggest another approach.

What worked for me is react-native-reanimated-carousel, which not only that is very easy to use and very customizable, but is also using react-native-reanimated and that means native performance and precise animations because it runs the animations on the UI thread rather than the JS thread.

EDIT: I noticed that you're actually looking for a reanimated answer, which is great!

Based on the library I showed you, I believe you're looking for a parallax horizontal.

Here's a link to the example: https://github.com/dohooo/react-native-reanimated-carousel/blob/main/exampleExpo/src/parallax/index.tsx

Related