Skip to content

Instantly share code, notes, and snippets.

@thenriquedb
Created April 15, 2025 14:28
Show Gist options
  • Save thenriquedb/de60bb37416a8054ec0394ce6d6f5ea2 to your computer and use it in GitHub Desktop.
Save thenriquedb/de60bb37416a8054ec0394ce6d6f5ea2 to your computer and use it in GitHub Desktop.
React Native Animated Galery
import React, { useEffect, useRef } from 'react';
import {
StatusBar,
FlatList,
Image,
View,
Dimensions,
StyleSheet,
TouchableOpacity,
} from 'react-native';
const { width, height } = Dimensions.get('screen');
const API_KEY = "hUbbPGwPyjAWi2FBj97Ez0hnUTW42mfCgS1mVmTc0MJLZFIMoW57FWJe"
const API_URL = "https://api.pexels.com/v1/search?query=space&orientation=portrait&size=small&per_page=20"
const IMAGE_SIZE = 80;
const SPACING = 10;
async function fetchImagesFromPexels() {
const response = await fetch(API_URL, {
method: 'GET',
headers: {
Authorization: API_KEY,
},
});
const { photos } = await response.json();
return photos;
}
export default () => {
const [images, setImages] = React.useState([]);
const [activeIndex, setActiveIndex] = React.useState(0);
const topRef = useRef();
const thumbRef = useRef();
async function fetchImages() {
const photos = await fetchImagesFromPexels();
setImages(photos);
}
function scrollToActiveIndex(index: number) {
setActiveIndex(index);
topRef?.current.scrollToOffset({
offset: index * width,
animated: true,
});
if (index * (IMAGE_SIZE + SPACING) - IMAGE_SIZE / 2 > width / 2) {
thumbRef?.current.scrollToOffset({
offset: index * (IMAGE_SIZE + SPACING) - width / 2 + IMAGE_SIZE / 2,
animated: true
})
} else {
thumbRef?.current.scrollToOffset({
offset: 0,
animated: true
})
}
// topRef.current.scrollToIndex({ index });
// thumbRef.current.scrollToIndex({ index });
}
useEffect(() => {
fetchImages();
}, [])
return (
<View style={{ flex: 1, backgroundColor: 'white' }}>
<StatusBar hidden />
<FlatList
ref={topRef}
data={images}
keyExtractor={(item) => item.id.toString()}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onMomentumScrollEnd={(e) => {
const index = Math.round(e.nativeEvent.contentOffset.x / width);
scrollToActiveIndex(index);
}}
renderItem={({ item }) => (
<View style={{ width, height }}>
<Image
source={{ uri: item.src.portrait }}
style={[StyleSheet.absoluteFillObject]}
/>
</View>
)}
/>
<FlatList
ref={thumbRef}
data={images}
keyExtractor={(item) => item.id.toString()}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
style={{
position: 'absolute',
bottom: 80,
}}
contentContainerStyle={{
padding: SPACING,
}}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={() => scrollToActiveIndex(index)}>
<Image
source={{ uri: item.src.portrait }}
style={{
width: IMAGE_SIZE,
height: IMAGE_SIZE,
borderRadius: 12,
marginRight: SPACING,
borderWidth: 2,
borderColor: index === activeIndex ? 'white' : 'transparent',
}}
/>
</TouchableOpacity>
)}
/>
</View>
);
};
@thenriquedb
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment