0

Thank you for the post. So I am following this example on my code, but my animation is not being triggered for some reason. The array from the useRef is being changed, but the animation is not working, any ideas of what could be the issue, here is my code. I am trying to expand my card to make the height bigger whenever the user press the View Information button. Thank you!

const animateCardAll = useRef([]);

{markersArr.map((marker, index) => {
          animateCardAll.current[index] = new Animated.Value(CARD_HEIGHT);
          marker.isExpanded = false;
          (marker.imageFetched = false), console.log(marker);
          return (
            <>
              <Animated.View
                key={marker._id}
                style={[
                  styles.card,
                  {
                    height: animateCardAll.current[index],
                  },
                ]}
              >
                {marker.imageId ? (
                  <LazyImage
                    index={index}
                    //visibleImages={visibleImages}
                    imageId={marker.imageId}
                    userToken={userToken}
                    ref={(cardRefs.current[index] = marker)}
                  />
                ) : null}
                <View style={styles.textContent}>
                  <Text style={styles.cardTitle} numberOfLines={1}>
                    Address: {marker.address}
                  </Text>
                  
                  <Text style={styles.cardDescription} numberOfLines={1}>
                    {marker.city}, {marker.zip_code} {marker.uSstate}
                  </Text>
                  
                  {cardRefs.current[index] &&
                  cardRefs.current[index].isExpanded ? (
                    <ReviewsComponent
                      index={index}
                      addressId={marker._id}
                      userToken={userToken}
                    />
                  ) : null}
                </View>

                <View style={styles.button}>
                  <TouchableOpacity
                    onPress={() => {
                      expandCardAll(index);
                    }}
                    style={[
                      styles.signIn,
                      {
                        borderColor: "#398984",
                        borderWidth: 1,
                      },
                    ]}
                  >
                    <Text
                      style={[
                        styles.textSign,
                        {
                          color: "#398984",
                        },
                      ]}
                    >
                      VIEW INFORMATION
                    </Text>
                  </TouchableOpacity>
                </View>
              </Animated.View>
            </>
          );
        })}
      </Animated.ScrollView>
    ) : null}

 const expandCardAll = (index) => {


cardRefs.current[index].isExpanded = !cardRefs.current[index].isExpanded; // Toggle the expanded state

const upadtedHeight = cardRefs.current[index].isExpanded
  ? SCREEN_HEIGHT * 0.65
  : CARD_HEIGHT;
console.log(
  "Expanded",
  cardRefs.current[index],
  animateCardAll.current[index],
  animateCardAll,
  upadtedHeight
);

Animated.timing(animateCardAll.current[index], {
  toValue: upadtedHeight,
  duration: 500,
  useNativeDriver: false,
}).start(); };

As I mentioned, the value in my animateCardAll.current[index] is being updated properly, but no animation is being triggered. Also, I am following the example on this link Example

AlohaBombai
  • 153
  • 1
  • 1
  • 7

1 Answers1

1

From the code snippet you've provided, it seems like you're creating a new Animated.Value for each item in the array every time the component re-renders. This is because of the Animated.Value initialization is inside the map function which is inside the render method. I think it could be the reason why your animations are not working as expected.

Instead, you should initialize the Animated.Value for each item only once, and then use these values to animate the items. You might do that:

const animateCardAll = useRef(markersArr.map(() => new Animated.Value(CARD_HEIGHT)));

const expandCardAll = (index) => {
  const updatedHeight = cardRefs.current[index].isExpanded
    ? SCREEN_HEIGHT * 0.65
    : CARD_HEIGHT;

  Animated.timing(animateCardAll.current[index], {
    toValue: updatedHeight,
    duration: 500,
    useNativeDriver: false,
  }).start();
};

return (
  <Animated.ScrollView>
    {markersArr.map((marker, index) => (
      <Animated.View
        key={marker._id}
        style={[
          styles.card,
          {
            height: animateCardAll.current[index],
          },
        ]}
      >
        {/* ...rest of your code... */}
      </Animated.View>
    ))}
  </Animated.ScrollView>
);

animateCardAll is a ref that holds an array of Animated.Value instances, one for each item in markersArr. The expandCardAll function updates the Animated.Value for the specified item and starts the animation. The height of each card is set to its corresponding Animated.Value, so it will animate when the value changes.

I assume that the markersArr array does not change after the component mounts. If items can be added or removed from the array, you'll need to handle that separately, for example by using a state variable to store the Animated.Value instances and update them when the array changes. Hope it works mate!

Erencan
  • 185
  • 6
  • Thank you so much for the feedback. It worked by adding mapping through the array and assigning the animated ref. Thank you again! – AlohaBombai Jun 18 '23 at 10:30
  • There is a problem with this solution though. When my component renders for the first time and the markersArr is undefined, I get that it cannot map from undefined. So I tried using useEffect to wait until the markersArr is populated, but then I get the error that it cannot convert undefined to object with the "height: animateCardAll.current[index]". Any thoughts on how to solve this other issue? Thank you! – AlohaBombai Jun 18 '23 at 10:52
  • One way to solve this issue would be to create animateCardAll within a useEffect hook that depends on markersArr. In this hook, you could check if markersArr is defined and non-empty, then populate animateCardAll: – Erencan Jun 19 '23 at 19:37
  • Thank you for the response. So, I will create the const animateCardAll = useRef() inside the useEffect? Then it will not be a global variable right? – AlohaBombai Jun 20 '23 at 20:55