2021-05-25 18:44:39 +02:00

95 lines
4.6 KiB
Plaintext

---
id: animated
title: Zooming with Reanimated
sidebar_label: Zooming with Reanimated
---
import useBaseUrl from '@docusaurus/useBaseUrl';
<div>
<svg xmlns="http://www.w3.org/2000/svg" width="283" height="535" style={{ float: 'right' }}>
<image href={useBaseUrl("img/demo.gif")} x="18" y="33" width="247" height="469" />
<image href={useBaseUrl("img/frame.png")} width="283" height="535" />
</svg>
</div>
## Animations
Often you'd want to animate specific props in the Camera. For example, if you'd want to create a custom zoom gesture, you can smoothly animate the Camera's `zoom` property.
The `<Camera>` component already provides a natively implemented zoom gesture which you can enable with the [`enableZoomGesture`](/docs/api/interfaces/cameraprops.cameraprops-1#enablezoomgesture) prop. This does not require any additional work, but if you want to setup a custom gesture, such as the one in Snapchat or Instagram where you move up your finger while recording, continue reading.
### Animation libraries
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](https://github.com/software-mansion/react-native-reanimated) (v2) to achieve best performance. Head over to their [Installation guide](https://docs.swmansion.com/react-native-reanimated/docs/installation) to install Reanimated if you haven't already.
### Implementation
The following example implements a button which smoothly zooms to a random value using [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated):
```tsx
import Reanimated, {
useAnimatedProps,
useSharedValue,
withSpring,
} from "react-native-reanimated"
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)
Reanimated.addWhitelistedNativeProps({
zoom: true,
})
export function App() {
const devices = useCameraDevices()
const device = devices.back
const zoom = useSharedValue(0)
const onRandomZoomPress = useCallback(() => {
zoom.value = withSpring(Math.random())
}, [])
const animatedProps = useAnimatedProps<Partial<CameraProps>>(
() => ({ zoom: zoom.value }),
[zoom]
)
if (device == null) return <LoadingView />
return (
<>
<ReanimatedCamera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
animatedProps={animatedProps}
/>
<TouchableOpacity
style={styles.zoomButton}
onPress={onRandomZoomPress}>
<Text>Zoom randomly!</Text>
</TouchableOpacity>
</>
)
}
```
### Explanation
1. The `Camera` was made animatable using `Reanimated.createAnimatedComponent`
2. The `zoom` property is added to the whitelisted native props to make it animatable.
> Note that this might not be needed in the future, see: [reanimated#1409](https://github.com/software-mansion/react-native-reanimated/pull/1409)
3. Using [`useSharedValue`](https://docs.swmansion.com/react-native-reanimated/docs/api/useSharedValue), we're creating a shared value that holds the value for the `zoom` property.
4. Using the [`useAnimatedProps`](https://docs.swmansion.com/react-native-reanimated/docs/api/useAnimatedProps) hook, we apply the shared value to Camera's `zoom` property.
5. We apply the animated props to the `ReanimatedCamera` component's `animatedProps` property.
### Logarithmic scale
A Camera's `zoom` property is represented in a **logarithmic scale**. That means, increasing from `0` to `0.1` will appear to be a much larger offset than increasing from `0.9` to `1`. 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](https://github.com/cuvent/react-native-vision-camera/tree/main/example), the pinch-to-zoom gesture can be found [here](https://github.com/cuvent/react-native-vision-camera/blob/d8551792e97eaa6fa768f54059ffce054bf748d9/example/src/CameraPage.tsx#L162-L176), and the pan-to-zoom gesture can be found [here](https://github.com/cuvent/react-native-vision-camera/blob/d8551792e97eaa6fa768f54059ffce054bf748d9/example/src/views/CaptureButton.tsx#L185-L205). 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.
<br />
#### 🚀 Next section: [Camera Errors](errors)