React Native Zoomable View
unknown
typescript
a year ago
2.0 kB
7
Indexable
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;
Editor is loading...
Leave a Comment