Skip to content

SnapbackZoom

An ideal component for preview handling, as its name suggests it returns to its original position after the pinch gesture ends, you can see this feature being implemented in Telegram's messages containing images and/or videos or Instragram's posts.

Beware iOS users

This component will be subject to some level of stuttering, unless you install a version of React Native Gesture Handler greater than equals 2.16.0.

For more information see this Gesture Handler's issue and this issue.

The next video footage is taken from the Example app

How to use

Its usage is pretty straight forward, import SnapBackZoom component from react-native-zoom-toolkit and wrap a component of your choice with it.

Tip

Do not use position: "absolute" in the wrapped component by SnapbackZoom as it messes up with pinch gesture's measurement, wrap SnapBackZoom within a absolute positioned view if you need so.

jsx
import { SnapBackZoom } from "react-native-zoom-toolkit"

// Simple use case
<SnapBackZoom>
  <Image // <= This could be an Expo image or a Video
    source={{ uri: IMAGE }}
    style={{ width: 200, height: 200 }}
    resizeMethod={"scale"} // <= Very important for images in Android do not forget it
    resizeMode={"cover"}/>
</SnapBackZoom>

// Complex use case
<SnapBackZoom
  hitSlop={{ vertical: 50, horizontal: 50 }}
  timingConfig={{ duration: 150, easing: Easing.linear }}
  onTap={(e) => console.log(e)}
  onDoubleTap={(e) => console.log(e)}
  onPinchStart={(e) => console.log(e)}
  onPinchEnd={(e) => console.log(e)}
  onGestureActive={(e) => {
    'worklet';
     console.log(e);
  }}
  onGestureEnd={() => console.log('animation finished!')}>
    <Image // <= This could be an Expo image or a Video
      source={{ uri: IMAGE }}
      style={{ width: 200, height: 200 }}
      resizeMethod={"scale"} // <= Very important for images in Android do not forget it
      resizeMode={"cover"}/>
</SnapBackZoom>

Properties

All properties for this component are optional.

hitslop

TypeDefaultAdditional Info
objectundefinedsee HitSlop

Increase (Android only) or decrease the gesture detection area around your component in all directions by a given amount in pixels, useful when dealing with small components.

timingConfig

TypeDefaultAdditional Info
objectundefinedsee TimingConfig

Custom React Native Reanimated's timing configuration used to snap back to the original position.

Tip

Be realistic with the timing configuration you use as you will not be able to resume the gesture once the snapback animation has started.

resizeConfig

TypeDefaultAdditional info
ResizeConfigundefinedsee notes

Dynamically recalculates SnapBackZoom component's width and height style properties to align with a given aspect ratio based on a scale value as the gesture scale increases.

gesturesEnabled

TypeDefault
booleantrue

Enables or disable gestures, when gestures are disabled your component can detect pointer events again.

onTap

TypeDefaultAdditional Info
functionundefinedsee tap gesture event data

Callback triggered when the user taps the wrapped component once, receives a tap gesture event as its only argument.

onDoubleTap

TypeDefaultAdditional Info
functionundefinedsee tap gesture event data

Callback triggered when the user taps the wrapped component twice, receives a tap gesture event as its only argument.

onPinchStart

TypeDefaultAdditional Info
functionundefinedsee pinch gesture event data

callback triggered when the pinch gesture starts, receives a pinch gesture event as its only argument.

onPinchEnd

TypeDefaultAdditional Info
functionundefinedsee pinch gesture event data

Callback triggered as soon as the user lifts their fingers off the screen after pinching, receives tap gesture event as its only argument.

onGestureActive

TypeDefaultAdditional Info
worklet functionundefinedsee worklets

Worklet callback triggered from the moment pinch gesture starts until the snap back animation finishes, receives an object of type SnapbackZoomState as its only argument.

Ideal if you need to mirror the current state of the gesture to some other component.

onGestureEnd

TypeDefault
functionundefined

Callback triggered once the snap back animation has finished.

Notes

On resizeConfig Property

Imagine you've got a lot of images you want to display as tiles of 200x200 pixel size, for many of those images the aspect ratio has been compromised, assume one of those images is 1920x1080 pixel size and you would like this image to resize in such a way the aspect ratio is no longer compromised when the image has been scaled two times by the pinch gesture, your object would look like this one.

javascript
{
  size: { width: 200, height: 200 }, // size of your tile
  aspectRatio: 1920 / 1080, // aspect ratio based on the size of your image/video
  scale: 2 // at which scale the aspect ratio is no longer compromised
}

Important

SnapbackZoom resizes its own dimensions not your component's ones, remember to use {width: '100%', height: '100%'} for images and videos so they cover the entire area of SnapBackZoom as it resizes.

At a scale of one your image is a tile of 200x200 pixel size, in other words a square, but at a scale two it resizes to 340x200 pixel size becoming a rectangle matching with the image's aspect ratio.

Type Definitions

ResizeConfig

Propertytypedescription
size{width: number; height: number;}Fields specify the width and height of your component.
aspectRationumberAspect ratio of your image/video/component.
scalenumberAt which scale your component will be fully resized to meet the aspect ratio.

SnapbackZoomState

NameTypeDescription
xnumberPosition in the x axis starting from the top left corner of the screen
ynumberPosition in the y axis starting from the top left corner of the screen
widthnumberInital width measurement of your component
heightnumberInital height measurement of your component
resizedWidthnumber | undefinedCurrent width measurement of your component, if resizeConfig property is undefined, this value will be undefined too
resizedHeightnumber | undefinedCurrent height measurement of your component, if resizeConfig property is undefined, this value will be undefined too
translateXnumberCurrent translateX transformation value
translateYnumberCurrent translateY transformation value
scalenumberCurrent scale transformation value

Released under the MIT License.