React Native Reanimated conditionally animate in array

209 Views Asked by At

I want to animate view in the list conditionally based on its position in the list. Here are the codes

   <GestureHandlerRootView style={{ flex: 1 }}>
      <GestureDetector gesture={pan}>
        <Animated.View
          ...
          >
          {props.children.map((children, index) => (
            <Animated.View
              style={[
                index === sharedActiveIndex.value ? activeItemAnimatedStyle : index === sharedActiveIndex.value + 1 ? nextItemAnimatedStyle : defaultAnimatedStyle,
              ]}>
              {children}
            </Animated.View>
          ))}
        </Animated.View>
      </GestureDetector>
    </GestureHandlerRootView>

As you see there is animated.view inside .map function. I want to animate the value based on its position in the array. I feel like this isn't the right way and its creating flickering issue upon release of drag, as you can see in this image below.

enter image description here

You can see full code and try here https://snack.expo.dev/k4EsyHF9j

What I can do to fix this?

1

There are 1 best solutions below

1
On BEST ANSWER

Well your point is correct. The issue is that you're updating the whole style. The trick is to keep the same style and animate just what you need (inside the same style).

Here's a hint:

{props.children.map((children, index) => {
     const rItemStyle = useAnimatedStyle(()=> {
          return {
             transform: [{
               scale: withTiming(index === sharedActiveIndex.value ? 1.2 : 1)
             }]
           }
      },[index])
    
      return <Animated.View
          style={[
            props.itemStyle,
            rItemStyle,
          ]}>
          ...
       </Animated.View>
 })}

Of course it's not a good idea to use "useAnimatedStyle" inside a hook. The best thing to do is to create another component that accepts both sharedActiveIndex (Animated.SharedValue) and index (number) as props, in order to shift this logic there.

By doing that the animation won't flicker anymore. But... the transition will happen only when the item is totally highlighted.

Wouldn't be great if the scale increases and decreases while scrolling? To do that you need to animate by using the interpolate function instead.

Maybe this tutorial can be helpful.