Zooming
Native Zoom Gesture​
The <Camera> component already provides a natively implemented zoom gesture which you can enable with the enableZoomGesture prop. If you don't need any additional logic in your zoom gesture, you can skip to the next section.
🚀 Next section: Focusing
If you want to setup a custom gesture, such as the one in Snapchat or Instagram where you move up your finger while recording, first understand how zoom is expressed.
Min, Max and Neutral Zoom​
A Camera device has different minimum, maximum and neutral zoom values. Those values are expressed through the CameraDevice's minZoom, maxZoom and neutralZoom props, and are represented in "scale". So if the maxZoom property of a device is 2, that means the view can be enlarged by twice it's zoom, aka the viewport halves.
- The
minZoomvalue is always1. - The
maxZoomvalue can have very high values (such as128), but often you want to clamp this value to something realistic like16. - The
neutralZoomvalue is often1, but can be larger than1for devices with "fish-eye" (ultra-wide-angle) cameras. In those cases, the user expects to be at whatever zoom valueneutralZoomis (e.g.2) per default, and if he tries to zoom out even more, he goes tominZoom(1), which switches over to the "fish-eye" (ultra-wide-angle) camera as seen in this GIF:

The Camera's zoom property expects values to be in the same "factor" scale as the minZoom, neutralZoom and maxZoom values - so if you pass zoom={device.minZoom} it is at the minimum available zoom, where as if you pass zoom={device.maxZoom} the maximum zoom value possible is zoomed in. It is recommended that you start at device.neutralZoom and let the user manually zoom out to the fish-eye camera on demand (if available).
Logarithmic scale​
A Camera's zoom property is represented in a logarithmic scale. That means, increasing from 1 to 2 will appear to be a much larger offset than increasing from 127 to 128. If you want to implement a zoom gesture (<PinchGestureHandler>, <PanGestureHandler>), try to flatten the zoom property to a linear scale by raising it exponentially. (zoom.value ** 2)
Pinch-to-zoom​
The above example only demonstrates how to animate the zoom property. To actually implement pinch-to-zoom or pan-to-zoom, take a look at the VisionCamera example app, the pinch-to-zoom gesture can be found here, and the pan-to-zoom gesture can be found here. They implement a real world use-case, where the maximum zoom value is clamped to a realistic value, and the zoom responds very gracefully by using a logarithmic scale.
Example (Reanimated + Gesture Handler)​
While you can use any animation library to animate the zoom property (or use no animation library at all) it is recommended to use react-native-reanimated to achieve best performance. Head over to their Installation guide to install Reanimated if you haven't already.
Overview​
- Make the Camera View animatable using
createAnimatedComponent - Make the Camera's
zoomproperty animatable usingaddWhitelistedNativeProps - Create a SharedValue using
useSharedValuewhich represents the zoom state (from0to1) - Use
useAnimatedPropsto map the zoom SharedValue to the zoom property. - We apply the animated props to the
ReanimatedCameracomponent'sanimatedPropsproperty.
Code​
The following example implements a pinch-to-zoom gesture using react-native-gesture-handler and react-native-reanimated:
import { Camera, useCameraDevice, CameraProps } from 'react-native-vision-camera'
import Reanimated, { useAnimatedProps, useSharedValue } from 'react-native-reanimated'
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
Reanimated.addWhitelistedNativeProps({
zoom: true,
})
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)
export function App() {
const device = useCameraDevice('back')
const zoom = useSharedValue(device.neutralZoom)
const zoomOffset = useSharedValue(0);
const gesture = Gesture.Pinch()
.onBegin(() => {
zoomOffset.value = zoom.value
})
.onUpdate(event => {
const z = zoomOffset.value * event.scale
zoom.value = interpolate(
z,
[1, 10],
[device.minZoom, device.maxZoom],
Extrapolation.CLAMP,
)
})
const animatedProps = useAnimatedProps<CameraProps>(
() => ({ zoom: zoom.value }),
[zoom]
)
if (device == null) return <NoCameraDeviceError />
return (
<GestureDetector gesture={gesture}>
<ReanimatedCamera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
animatedProps={animatedProps}
/>
</GestureDetector>
)
}
You can also use Gesture Handler to implement different zoom gestures, such as the slide-up-to-zoom as seen in Instagram or Snapchat, or a slider as seen in the stock iOS Camera app.