React Native Zoomable View

mail@pastecode.io avatar
unknown
typescript
4 days ago
2.0 kB
1
Indexable
Never
import React, {PropsWithChildren} from 'react';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import Animated, {
  clamp,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from 'react-native-reanimated';

type Props = {
  minScale?: number;
  maxScale?: number;
};

const ZoomableView = ({
  children,
  maxScale = 1.5,
  minScale = 1,
}: PropsWithChildren<Props>) => {
  const startScale = useSharedValue(0);
  const scale = useSharedValue(minScale);
  const startTranslationX = useSharedValue(0);
  const translateX = useSharedValue(0);

  const pinchHandler = Gesture.Pinch()
    .onBegin(() => {
      startScale.value = scale.value;
    })
    .onUpdate(({scale: eScale}) => {
      scale.value = clamp(startScale.value * eScale, minScale, maxScale);
    })
    .onEnd(() => {
      if (scale.value <= minScale) {
        scale.value = withSpring(minScale);
        translateX.value = withSpring(0);
      }
    });

  const panHandler = Gesture.Pan()
    .onBegin(() => {
      if (scale.value <= minScale) return;
      startTranslationX.value = translateX.value;
    })
    .onUpdate(({translationX}) => {
      if (scale.value > minScale) {
        translateX.value = clamp(
          startTranslationX.value + translationX,
          -100,
          100,
        );
      }
    });

  const tapHandler = Gesture.Tap()
    .numberOfTaps(2)
    .onEnd(() => {
      scale.value = withSpring(scale.value > minScale ? minScale : maxScale);
      translateX.value = withSpring(0);
    });

  const animatedStyle = useAnimatedStyle(() => {
    return {
      transform: [{scale: scale.value}, {translateX: translateX.value}],
    };
  });

  const gesture = Gesture.Simultaneous(pinchHandler, panHandler, tapHandler);

  return (
    <GestureDetector gesture={gesture}>
      <Animated.View style={[{flex: 1}, animatedStyle]}>
        {children}
      </Animated.View>
    </GestureDetector>
  );
};

export default ZoomableView;
Leave a Comment