https://github.com/saseungmin/react-native-gesture-image-viewer
๐ผ๏ธ A highly customizable and easy-to-use React Native image viewer with gesture support and external controls
https://github.com/saseungmin/react-native-gesture-image-viewer
android expo gallery image-gallery image-viewer ios photo-viewer react-native react-native-gesture-handler react-native-gesture-image-viewer react-native-image-viewer react-native-image-zoom-viewer react-native-reanimated react-native-reanimated-image-viewer viewer web
Last synced: about 1 month ago
JSON representation
๐ผ๏ธ A highly customizable and easy-to-use React Native image viewer with gesture support and external controls
- Host: GitHub
- URL: https://github.com/saseungmin/react-native-gesture-image-viewer
- Owner: saseungmin
- License: mit
- Created: 2025-06-30T15:10:12.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-08-13T10:36:30.000Z (about 2 months ago)
- Last Synced: 2025-08-13T11:42:59.592Z (about 2 months ago)
- Topics: android, expo, gallery, image-gallery, image-viewer, ios, photo-viewer, react-native, react-native-gesture-handler, react-native-gesture-image-viewer, react-native-image-viewer, react-native-image-zoom-viewer, react-native-reanimated, react-native-reanimated-image-viewer, viewer, web
- Language: TypeScript
- Homepage: https://react-native-gesture-image-viewer.pages.dev/
- Size: 39.1 MB
- Stars: 21
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README-ko_kr.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# React Native Gesture Image Viewer
> [English](./README.md) | ํ๊ตญ์ด
![]()
## ๊ฐ์
React Native์์ ์ด๋ฏธ์ง ๊ฐค๋ฌ๋ฆฌ๋ ์ฝํ ์ธ ๋ทฐ์ด๋ฅผ ๊ตฌํํ ๋, ๋ณต์กํ ์ ์ค์ฒ ์ฒ๋ฆฌ์ ์ ๋๋ฉ์ด์ ๊ตฌํ์ผ๋ก ์ด๋ ค์์ ๊ฒช์ผ์ ์ ์ด ์์ผ์ ๊ฐ์?
๊ธฐ์กด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ปค์คํฐ๋ง์ด์ง์ด ์ด๋ ต๊ฑฐ๋ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. `react-native-gesture-image-viewer`๋ React Native Reanimated์ Gesture Handler๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ๊ณ ์ฑ๋ฅ **๋ฒ์ฉ ์ ์ค์ฒ ๋ทฐ์ด** ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ด๋ฏธ์ง๋ฟ๋ง ์๋๋ผ ๋น๋์ค, ์ปค์คํ ์ปดํฌ๋ํธ ๋ฑ ๋ชจ๋ ์ฝํ ์ธ ์ ์์ ํ ์ปค์คํฐ๋ง์ด์ง๊ณผ ์ง๊ด์ ์ธ ์ ์ค์ฒ ์ง์์ ์ ๊ณตํฉ๋๋ค.
![]()
### ์ฃผ์ ํน์ง
- ๐ค **์์ ํ ์ ์ค์ฒ ์ง์** - ํ์น ์ค, ๋๋ธ ํญ ์ค, ์ค์์ดํ ๋ค๋น๊ฒ์ด์ , ์ค ์ํ์์์ ํฌ, ์ธ๋ก ๋๋๊ทธ๋ก ๋ซ๊ธฐ ์ง์
- ๐๏ธ **๊ณ ์ฑ๋ฅ ์ ๋๋ฉ์ด์ ** - React Native Reanimated ๊ธฐ๋ฐ์ 60fps ์ด์์ ๋ถ๋๋ฝ๊ณ ๋ฐ์์ฑ ๋์ ์ ๋๋ฉ์ด์
- ๐จ **์์ ํ ์ปค์คํฐ๋ง์ด์ง** - ์ปดํฌ๋ํธ, ์คํ์ผ, ์ ์ค์ฒ ๋์๊น์ง ์๋ฒฝํ๊ฒ ์ ์ด ๊ฐ๋ฅ
- ๐๏ธ **์ธ๋ถ ์ ์ด API** - ๋ฒํผ ๋ฑ ๋ค๋ฅธ UI ์ปดํฌ๋ํธ์์ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ์ ์ด ๊ฐ๋ฅ
- ๐งฉ **๋ค์ค ์ธ์คํด์ค ๊ด๋ฆฌ** - ๊ณ ์ ID ๊ธฐ๋ฐ์ผ๋ก ์ฌ๋ฌ ๋ทฐ์ด๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌ
- ๐งฌ **์ ์ฐํ ํตํฉ** - Modal, [React Native Modal](https://www.npmjs.com/package/react-native-modal), ScrollView, FlatList, [FlashList](https://www.npmjs.com/package/@shopify/flash-list), [Expo Image](https://www.npmjs.com/package/expo-image), [FastImage](https://github.com/DylanVann/react-native-fast-image) ๋ฑ ์ํ๋ ์ปดํฌ๋ํธ ์ฌ์ฉ
- ๐ง **์๋ฒฝํ TypeScript ์ง์** - ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๊ฐ์ถ ๋ฐ์ด๋ ๊ฐ๋ฐ ๊ฒฝํ ์ ๊ณต
- ๐ **ํฌ๋ก์ค ํ๋ซํผ ์ง์** - iOS, Android, Web์์ ๋์ํ๋ฉฐ Expo Go ๋ฐ New Architecture ์ง์
- ๐ช **๊ฐํธํ API** - ๋ณต์กํ ์ค์ ์์ด๋ ์ง๊ด์ ์ด๊ณ ์ฝ๊ฒ ๊ตฌํ ๊ฐ๋ฅ## ๋น ๋ฅธ ์์
### ๐ ๋ฌธ์
์ ์ฒด ๋ฌธ์๋ ์์ ํ์ธํ ์ ์์ต๋๋ค.
### ์์ ๋ฐ ๋ฐ๋ชจ
- [๐ ์์ ํ๋ก์ ํธ](/example/) - ์ค์ ๊ตฌํ ์ฝ๋์ ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก
- [๐ค Expo Go](https://snack.expo.dev/@harang/react-native-gesture-image-viewer) - Snack Expo์์ ๋ฐ๋ก ์ฒดํ### ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
`react-native-gesture-image-viewer`๋ ์์ ํ ์ปค์คํฐ๋ง์ด์ง์ ์ํด ์ ์ค์ฒ ๋์์๋ง ์ง์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
```tsx
import { useCallback, useState } from 'react';
import { ScrollView, Image, Modal, View, Text, Button, Pressable } from 'react-native';
import {
GestureViewer,
GestureTrigger,
useGestureViewerController,
useGestureViewerEvent,
} from 'react-native-gesture-image-viewer';function App() {
const images = [...];
const [visible, setVisible] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);const { goToIndex, goToPrevious, goToNext, currentIndex, totalCount } = useGestureViewerController();
const openModal = (index: number) => {
setSelectedIndex(index);
setVisible(true);
};const renderImage = useCallback((imageUrl: string) => {
return ;
}, []);useGestureViewerEvent('zoomChange', (data) => {
console.log(`Zoom changed from ${data.previousScale} to ${data.scale}`);
});return (
{images.map((uri, index) => (
openModal(index)}>
))}
setVisible(false)}
/>
goToIndex(2)} />
{`${currentIndex + 1} / ${totalCount}`}
);
}
```## ๊ธฐ์ฌํ๊ธฐ
ํ๋ก์ ํธ ๊ธฐ์ฌ ๋ฐฉ๋ฒ๊ณผ ๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ์ ๋ํ ์์ธํ ๋ด์ฉ์ [๊ธฐ์ฌ ๊ฐ์ด๋](CONTRIBUTING.md)๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
## ๋ผ์ด์ ์ค
[MIT](./LICENSE)