React Native Gallery Toolkit
Reanimated 2 and Gesturer Handler powered Gallery implementation
Important!
The library uses Reanimated 2 alpha. It means that it may be unstable. Also, the library itself is in the alpha testing stage and may contain bugs.
Installation
Use npm or yarn to install the library
npm i --save react-native-gallery-toolkit
Also, you need to install react-native-reanimated@2.0.0-alpha.7 (the new 2 version) and react-native-gesture-handler, and follow their installation instructions.
Expo is not currently supported because this library uses the latest version of Reanimated 2 (expo supports right now only alpha.6.1).
Standalone gallery
Standalone gallery renders Pager which supports thousands of images thanks to virtualization. Each page renders ImageTransformer component which gives ability to pinch-to-zoom, double tap to zoom, also you can run custom callbacks and worklets on on tab, double tap, pan.
import {
StandaloneGallery,
GalleryItemType,
StandaloneGalleryHandler,
} from 'react-native-gallery-toolkit';
const images: GalleryItemType[] = [
{
id: '1',
width: 300,
height: 300,
uri: 'https://placekitten.com/300/300',
},
{
id: '2',
width: 400,
height: 200,
uri: 'https://placekitten.com/400/200',
},
];
export default function App() {
return <StandaloneGallery items={images} />;
}
See Full featured example for example of usage of all the props.
Limitations
- Only portrait orientation currently supported
- There is no way to change dimensions without full re-render of the gallery
- Debugging is not supported because of Reanimated v2 uses TurboModules. Use flipper to debug your JS Context.
- On Android tap on hold on the screen while page changes doesn't trigger animation to stop due to bug in Gesture Handler.
Base props
Prop | Description | Type | Default |
---|---|---|---|
items |
The array of items to render. But can also accept Map, Set, or Object with keys. If the type is not array, then getTotalCount and getItem should be defined too. |
Array<{ width: number, height: number, id: string, uri: string }> |
undefined |
width? |
Viewport width | number |
Dimensions.get('window').width |
height? |
Viewport height | number |
Dimensions.get('window').height |
numToRender? |
How many pages should be rendered at the same time | number |
2 |
gutterWidth? |
The width of the gutter between pages | number |
0 |
initialIndex? |
The initial page index | number |
0 |
keyExtractor? |
Callback which extract the key of the page. Receives current item of the provided items as well as current index |
(item: T, index: number) => string |
Uses index as a key by default |
Advance props
Prop | Description | Type | Default |
---|---|---|---|
getTotalCount? |
If the type of items is not an array, then this method should be defined to provide the total count of items |
(data: T) => number |
Required when items is not an array |
getItem? |
If the type of items is not an array, then this method should be defined to provide the current item based on the index. Can return either the item or undefined . |
(data: T, index: number) => ItemT or undefined |
Required when items is not an array |
renderImage? |
Callback that can be used to render custom image component. As an example, it can be used to render custom loading/error states | (props: RenderImageProps, item: ItemT, index: number) => JSX.Element |
() => Image |
renderPage? |
Callback that can be used to render custom page. Can be used to display some non-image pages such as Video, for instance | (props: ImageRendererProps<T>, index: number) => JSX.Element |
ImageTransformer |
Handlers
Prop | Description | Type | Is worklet? | Default |
---|---|---|---|---|
onIndexChange? |
Fires when active index changes | (nextIndex: number) => void |
Function or Worklet |
undefined |
onTap? |
Executes when tap image transformer receives tap | () => void |
Function or Worklet |
undefined |
onDoubleTap? |
Executes when tap image transformer receives double-tap | () => void |
Function or Worklet |
undefined |
onInteraction? |
Is called when either pan or scale has happened. | (type: 'scale' or 'pan') => void |
Function or Worklet |
undefined |
onPagerTranslateChange? |
Executes on pager's horizontal pan | (translateX: number) => void |
Function or Worklet |
undefined |
onGesture? |
Executes on pager's gesture | (event: PanGestureHandlerGestureEvent, isActive: SharedValue<boolean>) => void |
Function or Worklet |
undefined |
shouldPagerHandleGestureEvent? |
Worklet that will be passed to pager's shouldHandleEvent to determine should pager handle this event. Can be used to handle "swipe down to close". |
(event: PanGestureHandlerGestureEvent) => boolean |
Only Worklet |
undefined |
Methods
Name | Description | Type |
---|---|---|
goNext |
Changes the active index forward | () => void |
goBack |
Changes the active index backward | () => void |
setIndex |
Sets the active index | (nextIndex: number) => void |
Pager
TODO
Transformer
TODO
Scalable Image
TODO
Examples
The source code for the example (showcase) app is under the Example/
directory.
Clone the repo, go to the Example/ folder and run:
npm install
Running on iOS
Before running the app, install the cocoapods dependencies:
npx pod-install
Now, you can start the app:
npm run ios
Running on Android
npm run android
TODOs
- Add invariants to all the required props
- Finish documentation
- Lightbox with examples
- Lightbox Gallery with examples
- Try to use react-native-shared-element