Storing references to all elements of a ScrollView

Viewed 25

I'm trying to implement a horizontal scrollable filter that functions similar to that of Airbnb (see image below).

enter image description here

I'm having trouble keeping the references to each view element that is part of the scrollview. I'm doing this to keep track of the width of each view (because they're variable) and where their content offset is so I can snap to the closest element after scrolling has stopped. The problem I'm having is that it's not assigning each reference into my shared value when the onLayout is called. Am I missing something? Any help would be appreciated.

Here's is a sample of what I have so far.

const DiscoverSportFilter = () => {
  const sports = useSelector(getSports);
  const sportTileDimensions = useSharedValue({});
  const position = useSharedValue(0);
  const animatedRef = useAnimatedRef<Animated.ScrollView>();

  const scrollToNearestItem = (offset: number) => {
    'worklet';
    console.log('sportTileDimensions.current', sportTileDimensions.value);

    // do some scrolling stuff
  };

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (e, ctx) => {
      position.value = e.contentOffset.x;
    },
    onMomentumEnd: (e, ctx) => {
      scrollToNearestItem(e.contentOffset.x);
    },
  });

  const SportTile = ({ name }) => {
    return (
      <View
        onLayout={({ nativeEvent }) => {
          const { x, width } = nativeEvent.layout;
          sportTileDimensions.value = {
            ...sportTileDimensions.value,
            [name.toLowerCase()]: { x, width },
          };
        }}
        style={{ padding: 10, alignItems: 'center' }}>
        <CustomIcon
          style={{ marginBottom: 5 }}
          name={getSportIcon(name)}
          size={24}
        />
        <Text style={{ fontSize: 12 }}>{name}</Text>
      </View>
    );
  };

  return (
    <Animated.ScrollView
      ref={animatedRef}
      style={{ flexGrow: 0 }}
      horizontal
      showsHorizontalScrollIndicator={false}
      onScroll={scrollHandler}
      scrollEventThrottle={1}>
      {sports.map(({ name }) => (
        <SportTile key={name} name={name} />
      ))}
    </Animated.ScrollView>
  );
};

The current implementation seems to store only 1 result from the list of sports so I'm a little confused on what is happening.

0 Answers
Related