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.
Implementation (Reanimated)
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 button which smoothly zooms to a random value using react-native-reanimated:
import Reanimated, {
useAnimatedProps,
useSharedValue,
withSpring,
addWhitelistedNativeProps
} from "react-native-reanimated"
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)
addWhitelistedNativeProps({
zoom: true,
})
export function App() {
const device = useCameraDevice('back')
const zoom = useSharedValue(0)
const onRandomZoomPress = useCallback(() => {
zoom.value = withSpring(Math.random())
}, [zoom])
const animatedProps = useAnimatedProps<Partial<CameraProps>>(
() => ({ zoom: zoom.value }),
[zoom]
)
if (device == null) return <NoCameraDeviceError />
return (
<>
<ReanimatedCamera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
animatedProps={animatedProps}
/>
<TouchableOpacity
style={styles.zoomButton}
onPress={onRandomZoomPress}>
<Text>Zoom randomly!</Text>
</TouchableOpacity>
</>
)
}