Skip to content

Commit f9bf5fe

Browse files
committed
feat(gallery): enhance gallery and image viewer components
- Add custom header and footer rendering support - Implement thumbnail previews for images - Add new customization props - Improve image viewer with loading indicator and pan-down-to-close - Update documentation with usage examples
1 parent b163157 commit f9bf5fe

File tree

7 files changed

+743
-230
lines changed

7 files changed

+743
-230
lines changed

README.md

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,39 @@ yarn add @duocvo/react-native-gesture-image
2222

2323
## Usage
2424

25-
```js
25+
```jsx
26+
import React, { useRef } from 'react';
27+
import { View, StyleSheet, TouchableOpacity, Image } from 'react-native';
2628
import Gallery from '@duocvo/react-native-gesture-image';
2729

28-
// Example usage of Gallery
2930
export default function App() {
31+
const galleryRef = useRef(null);
32+
3033
const images = [
3134
{ uri: 'https://picsum.photos/200/300' },
3235
{ uri: 'https://picsum.photos/200/300' },
3336
{ uri: 'https://picsum.photos/200/300' },
34-
]
37+
];
38+
3539
return (
3640
<View style={styles.container}>
37-
<Gallery data={images} />
41+
{/* Thumbnail images that open the gallery when tapped */}
42+
<View style={styles.thumbnails}>
43+
{images.map((image, index) => (
44+
<TouchableOpacity
45+
key={index}
46+
onPress={() => galleryRef.current?.show(index)}
47+
>
48+
<Image source={image} style={styles.thumbnail} />
49+
</TouchableOpacity>
50+
))}
51+
</View>
52+
53+
{/* Gallery component */}
54+
<Gallery
55+
ref={galleryRef}
56+
data={images}
57+
/>
3858
</View>
3959
);
4060
}
@@ -43,6 +63,16 @@ const styles = StyleSheet.create({
4363
container: {
4464
flex: 1,
4565
},
66+
thumbnails: {
67+
flexDirection: 'row',
68+
flexWrap: 'wrap',
69+
padding: 10,
70+
},
71+
thumbnail: {
72+
width: 100,
73+
height: 100,
74+
margin: 5,
75+
},
4676
});
4777
```
4878
@@ -58,6 +88,103 @@ const styles = StyleSheet.create({
5888
| `containerStyle` | `object` | | Custom style for the gallery container | No |
5989
| `contentContainerStyle` | `object` | | Custom style for the content container | No |
6090
| `backdropColor` | `string` | `black` | Background color of the gallery | No |
91+
| `initialIndex` | `number` | `0` | Initial index of the image to display | No |
92+
| `enablePanDownToClose`| `boolean`| `false` | Enable closing the gallery by panning down | No |
93+
| `renderHeader` | `function`| | Custom header component | No |
94+
| `renderFooter` | `function`| | Custom footer component | No |
95+
96+
### Gallery Ref Methods
97+
98+
| Method | Parameters | Description |
99+
|-----------------------|------------|--------------------------------------------------|
100+
| `show` | `index?: number` | Show the gallery, optionally at a specific index |
101+
| `hide` | - | Hide the gallery |
102+
103+
## Examples
104+
105+
### Basic Usage with Header and Footer
106+
107+
```jsx
108+
import React, { useRef } from 'react';
109+
import { View, StyleSheet, TouchableOpacity, Image, Text } from 'react-native';
110+
import Gallery from '@duocvo/react-native-gesture-image';
111+
112+
export default function App() {
113+
const galleryRef = useRef(null);
114+
115+
const images = [
116+
{ uri: 'https://picsum.photos/200/300' },
117+
{ uri: 'https://picsum.photos/200/300' },
118+
{ uri: 'https://picsum.photos/200/300' },
119+
];
120+
121+
return (
122+
<View style={styles.container}>
123+
{/* Thumbnail images that open the gallery when tapped */}
124+
<View style={styles.thumbnails}>
125+
{images.map((image, index) => (
126+
<TouchableOpacity
127+
key={index}
128+
onPress={() => galleryRef.current?.show(index)}
129+
>
130+
<Image source={image} style={styles.thumbnail} />
131+
</TouchableOpacity>
132+
))}
133+
</View>
134+
135+
{/* Gallery component with custom header and footer */}
136+
<Gallery
137+
ref={galleryRef}
138+
data={images}
139+
renderHeader={() => (
140+
<View style={styles.header}>
141+
<TouchableOpacity onPress={() => galleryRef.current?.hide()}>
142+
<Text style={styles.headerText}>Close</Text>
143+
</TouchableOpacity>
144+
</View>
145+
)}
146+
renderFooter={() => (
147+
<View style={styles.footer}>
148+
<Text style={styles.footerText}>Image Caption</Text>
149+
</View>
150+
)}
151+
/>
152+
</View>
153+
);
154+
}
155+
156+
const styles = StyleSheet.create({
157+
container: {
158+
flex: 1,
159+
},
160+
thumbnails: {
161+
flexDirection: 'row',
162+
flexWrap: 'wrap',
163+
padding: 10,
164+
},
165+
thumbnail: {
166+
width: 100,
167+
height: 100,
168+
margin: 5,
169+
},
170+
header: {
171+
padding: 16,
172+
flexDirection: 'row',
173+
justifyContent: 'space-between',
174+
},
175+
headerText: {
176+
color: 'white',
177+
fontSize: 16,
178+
},
179+
footer: {
180+
padding: 16,
181+
},
182+
footerText: {
183+
color: 'white',
184+
fontSize: 14,
185+
},
186+
});
187+
```
61188
62189
## Contributing
63190

example/src/App.tsx

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,65 @@
1-
import { StyleSheet, View } from 'react-native';
2-
import React from 'react';
3-
import Gallery from '@duocvo/react-native-gesture-image';
1+
import {
2+
FlatList,
3+
Image,
4+
StyleSheet,
5+
Text,
6+
TouchableOpacity,
7+
View,
8+
} from 'react-native';
9+
import React, { useRef } from 'react';
10+
import Gallery, { GalleryRef } from '@duocvo/react-native-gesture-image';
411

512
const image1 = require('../assets/image1.jpeg');
613
const image2 = require('../assets/image2.jpeg');
714
const image3 = require('../assets/image3.jpeg');
815

916
export default function App() {
17+
const galleryRef = useRef<GalleryRef>(null);
18+
const data = [image1, image2, image3];
19+
1020
return (
1121
<View style={styles.container}>
12-
<Gallery data={[image1, image2, image3]} />
22+
<FlatList
23+
data={data}
24+
renderItem={({ item, index }) => (
25+
<TouchableOpacity onPress={() => galleryRef.current?.show(index)}>
26+
<View>
27+
<Image source={item} style={{ width: 300, height: 300 }} />
28+
</View>
29+
</TouchableOpacity>
30+
)}
31+
horizontal
32+
style={{ flex: 1 }}
33+
ItemSeparatorComponent={() => <View style={{ width: 20 }} />}
34+
contentContainerStyle={styles.flatList}
35+
/>
36+
37+
<Gallery
38+
ref={galleryRef}
39+
data={data}
40+
renderHeader={() => (
41+
<View
42+
style={{
43+
flexDirection: 'row',
44+
justifyContent: 'space-between',
45+
paddingHorizontal: 16,
46+
marginTop: 70,
47+
}}
48+
>
49+
<TouchableOpacity onPress={() => galleryRef.current?.hide()}>
50+
<Text style={{ color: 'white' }}>close button</Text>
51+
</TouchableOpacity>
52+
<TouchableOpacity>
53+
<Text style={{ color: 'white' }}>setting button</Text>
54+
</TouchableOpacity>
55+
</View>
56+
)}
57+
renderFooter={() => (
58+
<View style={{ marginBottom: 70, paddingHorizontal: 16 }}>
59+
<Text style={{ color: 'white' }}>image caption</Text>
60+
</View>
61+
)}
62+
/>
1363
</View>
1464
);
1565
}
@@ -18,4 +68,9 @@ const styles = StyleSheet.create({
1868
container: {
1969
flex: 1,
2070
},
71+
flatList: {
72+
paddingHorizontal: 20,
73+
justifyContent: 'center',
74+
alignItems: 'center',
75+
},
2176
});

0 commit comments

Comments
 (0)