Skip to content

Commit 1472060

Browse files
committed
code base
1 parent 9db2952 commit 1472060

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { AnimatedGallery } from './src/AnimatedGallery'
2+
3+
export default AnimatedGallery;

src/AnimatedGallery.tsx

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import * as React from 'react';
2+
import {
3+
FlatList,
4+
Image,
5+
Text,
6+
View,
7+
Dimensions,
8+
StyleSheet,
9+
TouchableOpacity,
10+
} from 'react-native';
11+
import {animatedGalleryProps} from './AnimatedGallery.type';
12+
13+
const {width, height} = Dimensions.get('screen');
14+
15+
export const AnimatedGallery = (props: animatedGalleryProps) => {
16+
/**
17+
* Props recived by animated gallery
18+
*/
19+
20+
const {
21+
imageUrls,
22+
spacing,
23+
thumpBorderWidth,
24+
thumpBorderColor,
25+
imageSize,
26+
renderLoader,
27+
disablefullScreen,
28+
} = props;
29+
30+
/**
31+
* Refs for handling the communication between two FlatList
32+
*/
33+
34+
const topRef = React.useRef();
35+
const thumpRef = React.useRef();
36+
37+
/**
38+
* Local state to keep the images array recevied as props
39+
*/
40+
41+
const [images, setImgaes] = React.useState<any>(null);
42+
43+
/**
44+
* active index Keeps track of the selected index or active index
45+
*/
46+
47+
const [activeIndex, setActiveIndex] = React.useState(0);
48+
49+
/**
50+
* If props are present then value from the props are applied else default value
51+
*/
52+
53+
const IMAGE_SIZE = imageSize ? imageSize : 80;
54+
const SPACING = spacing ? spacing : 10;
55+
const THUMP_BORDER_WIDTH = thumpBorderWidth ? thumpBorderWidth : 2;
56+
const THUMP_BORDER_COLOR = thumpBorderColor ? thumpBorderColor : '#ffff';
57+
58+
/**
59+
* when the compoent mounts the value from the imageUrl props is locally saved to images state
60+
*/
61+
62+
React.useEffect(() => {
63+
if (imageUrls.length !== 0) {
64+
setImgaes(imageUrls);
65+
}
66+
}, [imageUrls]);
67+
68+
/**
69+
Scroll to active index accepts index of the curent position as argument and onPress of the thumpNail
70+
parent flatlist item will be pushed to the current screnn by calculating the offset value to which the rendered item need to be moved
71+
72+
*/
73+
74+
const scrollToActiveIndex = (index: any) => {
75+
setActiveIndex(index);
76+
77+
topRef?.current?.scrollToOffset({
78+
offset: index * width,
79+
Animated: true,
80+
});
81+
82+
if (index * (IMAGE_SIZE + SPACING) - IMAGE_SIZE / 2 > width / 2) {
83+
thumpRef?.current?.scrollToOffset({
84+
offset: index * (IMAGE_SIZE + SPACING) - width / 2 + IMAGE_SIZE / 2,
85+
animated: true,
86+
});
87+
} else {
88+
thumpRef?.current?.scrollToOffset({
89+
offset: 0,
90+
animated: true,
91+
});
92+
}
93+
};
94+
95+
/**
96+
* Renders the custom loader if present
97+
*/
98+
99+
if (!images) {
100+
if (renderLoader) {
101+
return renderLoader;
102+
} else {
103+
return (
104+
<View style={{justifyContent: 'center', alignItems: 'center', flex: 1}}>
105+
<Text>Loading...</Text>
106+
</View>
107+
);
108+
}
109+
}
110+
111+
/**
112+
* Renders the main component
113+
*/
114+
115+
return (
116+
<View style={{flex: 1, backgroundColor: 'black'}}>
117+
<FlatList
118+
ref={topRef}
119+
data={images}
120+
keyExtractor={item => item.id.toString()}
121+
horizontal
122+
pagingEnabled
123+
showsVerticalScrollIndicator={false}
124+
showsHorizontalScrollIndicator={false}
125+
onMomentumScrollEnd={e => {
126+
scrollToActiveIndex(
127+
Math.floor(e.nativeEvent.contentOffset.x / width),
128+
);
129+
}}
130+
renderItem={({item}) => {
131+
return (
132+
<View style={{width: width, height: height}}>
133+
<Image
134+
source={{uri: item.url}}
135+
style={
136+
disablefullScreen
137+
? {
138+
width: width,
139+
height: width / 1.3,
140+
alignSelf: 'center',
141+
justifyContent: 'center',
142+
top: width / 1.5,
143+
}
144+
: [StyleSheet.absoluteFillObject]
145+
}
146+
/>
147+
</View>
148+
);
149+
}}
150+
/>
151+
152+
<FlatList
153+
data={images}
154+
ref={thumpRef}
155+
keyExtractor={item => item.id.toString()}
156+
horizontal
157+
pagingEnabled
158+
showsHorizontalScrollIndicator={false}
159+
contentContainerStyle={{paddingHorizontal: SPACING}}
160+
style={{position: 'absolute', bottom: IMAGE_SIZE}}
161+
renderItem={({item, index}) => {
162+
return (
163+
<TouchableOpacity onPress={() => scrollToActiveIndex(index)}>
164+
<Image
165+
source={{uri: item.url}}
166+
style={[
167+
{
168+
width: IMAGE_SIZE,
169+
height: IMAGE_SIZE,
170+
borderRadius: 12,
171+
marginRight: SPACING,
172+
borderWidth: THUMP_BORDER_WIDTH,
173+
borderColor:
174+
activeIndex === index
175+
? THUMP_BORDER_COLOR
176+
: 'transparent',
177+
},
178+
]}
179+
/>
180+
</TouchableOpacity>
181+
);
182+
}}
183+
/>
184+
</View>
185+
);
186+
};

src/AnimatedGallery.type.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { ReactElement } from 'react';
2+
3+
4+
export type animatedGalleryProps = {
5+
/**
6+
* Provides Data to the component
7+
*/
8+
imageUrls: Array<any>;
9+
10+
/**
11+
* Provides custom loader to component
12+
*/
13+
renderLoader?: ReactElement;
14+
15+
/**
16+
* Set the size of the thump nail to square proprtion.
17+
*/
18+
19+
imageSize?: number;
20+
21+
/**
22+
* Set the sapcing between thump nail
23+
*/
24+
spacing?: number;
25+
26+
/**
27+
* Set the border width for thump nail
28+
*/
29+
thumpBorderWidth?: number;
30+
31+
32+
/**
33+
* Set the border color for thump nail
34+
*/
35+
thumpBorderColor?: string;
36+
37+
38+
/**
39+
* Set the border color for thump nail
40+
*/
41+
disablefullScreen?: boolean;
42+
43+
44+
45+
};

0 commit comments

Comments
 (0)