I'm trying to implement a horizontal scrollable filter that functions similar to that of Airbnb (see image below).
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.
