Skip to content

ResumableZoom

An ideal and practical component for detail screens, all gestures are resumable and will pick up where you left in your last interaction with the component.

Among its more remarkable features you will find:

  • Pan Gesture: Drag and your components around in three different modes, optionally let your component slide with a decay animation.
  • Pinch Gesture: Accurate pinch gesture calculation, drag your component around as you pinch, scale your component in two different modes.
  • Double Tap: Tap twice in a point of interest to trigger a zoom animation.

The next video footage is taken from the Example app.

How to use

Its usage is pretty straight forward, just wrap a component of your choice with it, the following example is a full screen image detail component.

Tip

This component is best utilized when at least one of the two dimensions of the wrapped component is bigger than equals the space it's occupying in the screen, for instance if it's a full screen image detail screen, your image should be as wide or as tall as the size of your screen.

jsx
import React from 'react';
import { Image, useWindowDimensions } from 'react-native';
import {
  ResumableZoom,
  getAspectRatioSize,
  useImageResolution,
} from 'react-native-zoom-toolkit';

const uri =
  'https://assets-global.website-files.com/63634f4a7b868a399577cf37/64665685a870fadf4bb171c2_labrador%20americano.jpg';

const App = () => {
  const { width } = useWindowDimensions();

  // Gets the resolution of your image
  const { isFetching, resolution } = useImageResolution({ uri });
  if (isFetching || resolution === undefined) {
    return null;
  }

  // An utility function to get the size without compromising the aspect ratio
  const imageSize = getAspectRatioSize({
    aspectRatio: resolution.width / resolution.height,
    width: width,
  });

  return (
    <ResumableZoom maxScale={resolution}>
      <Image source={{ uri }} style={{ ...imageSize }} resizeMethod={'scale'} />
    </ResumableZoom>
  );
};

export default App;

Properties

All properties for this component are optional.

style

TypeDefault
ViewStyle{ flex: 1 }

Styles used by the container enclosing your component. The following styles are enforced by the library and can not be modified: { justifyContent: 'center', alignItems: 'center' }.

extendGestures

TypeDefault
booleanfalse

By default the gesture detection area is the same size as the width and height of the wrapped component, by setting this property to true the detection area is increased to the size ResumableZoom is taking on screen, see this picture for a visual reference.

minScale

TypeDefault
number1

Minimum scale value allowed by the pinch gesture, expects values greater than or equals one.

maxScale

TypeDefault
SizeVector<number> | number6

Maximum scale value allowed by the pinch gesture, expects values bigger than or equals one.

Alternatively you can pass the resolution of your image/video, for instance { width: 1920, height: 1080 }; this will instruct the component to calculate maxScale in such a way it's a value just before your content starts to pixelate.

panMode

TypeDefault
'clamp' | 'free' | 'friction''clamp'

Determine how your component must behave when it's panned beyond the specified boundaries by the container enclosing it, possible values are:

  • clamp prevents the user from dragging the component out of its enclosing container boundaries.
  • free lets the user drag the component around freely, if the pan gesture ends in an out of bounds position it will animate back to a position within the boundaries of its enclosing container.
  • friction is the same as freemode, however it adds some amount of friction as you pan.

scaleMode

TypeDefault
'clamp' | 'bounce''bounce'

Determine how your component must behave when the pinch gesture's scale value exceeds boundaries defined by minScale and maxScale properties, possible values are:

  • clamp keeps the scale whithin the already mentioned scale boundaries.
  • bounce lets the user scale above and below the scale boundary values, at the end of the pinch gesture the scale value animates back to minScale or maxScale respectively.

allowPinchPanning

TypeDefault
booleantrue

Lets the user pan the component around as they pinch as well as providing a more accurate pinch gesture calculation to user interaction. Panning as you pinch will not trigger any pan gesture related callbacks.

pinchCenteringMode

TypeDefault
'clamp' | 'sync''clamp'

Requirements

Requires allowPinchPanning property is set to true.

Determine the behavior used by the pinch gesture relative to the boundaries of its enclosing component, possible values are:

  • clamp keeps the pinch gesture clamped to the borders or its enclosing container during the entirity of the gesture, just like seen on Android galleries.
  • sync keeps the pinch gesture in sync with user interaction, if the pinch gesture was released in an out bonds position it will animate back to a position within the bondaries of its enclosing container.

decay

TypeDefaultAdditional Info
booleantruesee WithDecay

Whether to apply a decay animation when the pan gesture ends or not.

panEnabled

TypeDefault
booleantrue

Enables and disables both pan and swipe gestures.

pinchEnabled

TypeDefault
booleantrue

Enables and disables the pinch gesture.

tapsEnabled

TypeDefault
booleantrue

Enables and disables both single and double tap gestures.

onTap

TypeDefaultAdditional Info
(e: TapGestureEvent) => voidundefinedsee tap gesture event data

Callback triggered when the user taps the wrapped component once.

onSwipe

TypeDefault
(direction: 'up' | 'down' | 'left' | 'right') => voidundefined

Requirements

Requires panMode property is set to 'clamp'.

Callback triggered when the user swipes up, down, left or right.

onPanStart

TypeDefaultAdditional Info
(e: PanGestureEvent) => voidundefinedsee pan gesture event data

Callback triggered when the pan gesture starts.

onOverPanning

TypeDefaultAdditional Info
(x: number, y: number) => voidundefinedsee worklets

Worklet callback triggered when the wrapped component has been panned beyond the boundaries defined by its enclosing container, receives as an argument the amount the component has been panned beyond such boundaries in both x and y axis.

onPanEnd

TypeDefaultAdditional Info
(e: PanGestureEvent) => voidundefinedsee pan gesture event data

Callback triggered as soon as the user lifts their finger off the screen.

onPinchStart

TypeDefaultAdditional Info
(e: PinchGestureEvent) => voidundefinedsee pinch gesture event data

Callback triggered when the pinch gesture starts.

onPinchEnd

TypeDefaultAdditional Info
(e: PinchGestureEvent) => voidundefinedsee pinch gesture event data

Callback triggered as soon as the user lifts their fingers off the screen after pinching.

onUpdate

TypeDefaultAdditional Info
(state: CommonZoomState<number>) = voidundefinedsee worklets

Worklet callback triggered when the transformation state of the component changes, the internal state is updated as the user makes use of the gestures or execute its methods, ideal if you need to mirror its current transformation values to some other component as it updates, see CommonZoomState.

onGestureEnd

TypeDefault
() => voidundefined

Callback triggered when a pan, pinch or double tap gesture ends, if an animation started at the end of one of the gestures the execution of this callback will be delayed until such animation finishes.

Methods

All methods are accessible through a ref object.

tsx
import { useRef } from 'react';
import {
  ResumableZoom,
  type ResumableZoomType,
} from 'react-native-zoom-toolkit';

const ref = useRef<ResumableZoomType>(null);
ref.current?.reset(false);

<ResumableZoom ref={ref}>
  <SomeComponent />
</ResumableZoom>;

reset

Reset all transformations to their initial state.

  • type definition: (animate?: boolean) => void
  • parameter information
NameTypeDefaultDescription
animateboolean | undefinedtrueWhether to animate the transition or not.

zoom

Programmatically zoom in or out to a xy position within the child component.

  • type definition: (multiplier: number, xy?: Vector<number>) => void
  • parameter information
NameTypeDescription
multipliernumberValue to multiply the current scale for, values greater than one zoom in and values less than one zoom out.
xyVector<number> | undefinedPosition of the point to zoom in or out starting from the top left corner of your component, leaving this value as undefined will be infered as zooming in or out from the center of the child component's current visible area.

requestState

Request internal transformation values of this component at the moment of the calling.

assignState

Assign the internal transformation values for this component, if the state you have provided is considered to be not achievable by the component's boundaries, it'll be approximated to the closest valid state.

  • type definition: (state: ResumableZoomAssignableState, animate?: boolean) => void
  • parameter information
NameTypeDescription
stateResumableZoomAssignableStateObject containg the transformation values to assign to ResumableZoom component.
animateboolean | undefinedWhether to animate the transition or not, defaults to true.

Type Definitions

CommonZoomState

PropertyTypeDescription
widthnumberWidth of the wrapped component.
heightnumberHeight of the wrapped component.
translateXnumberCurrent translateX transformation value.
translateYnumberCurrent translateY transformation value.
scalenumberCurrent scale transformation value.

ResumableZoomAssignableState

PropertyTypeDescription
translateXnumberTranslateX transformation value.
translateYnumberTranslateY transformation value.
scalenumberScale transformation value.

Released under the MIT License.