Skip to content

Instantly share code, notes, and snippets.

@eveningkid
Created February 19, 2021 17:54
Show Gist options
  • Save eveningkid/3a23c5a5a2273981ed0ea602d2a2e1f9 to your computer and use it in GitHub Desktop.
Save eveningkid/3a23c5a5a2273981ed0ea602d2a2e1f9 to your computer and use it in GitHub Desktop.
React Native Pan Responder example to pan/scale an image
import React, { useRef } from 'react';
import {
Animated,
Image,
PanResponder,
useWindowDimensions,
} from 'react-native';
const IMAGE_URI =
'https://vignette.wikia.nocookie.net/joke-battles/images/4/40/18360-doge-doge-simple.jpg/revision/latest?cb=20151209161638';
const pointsDistance = ([xA, yA], [xB, yB]) => {
return Math.sqrt(
Math.pow(xA - xB, 2) + Math.pow(yA - yB, 2)
);
};
export default (props) => {
const dimensions = useWindowDimensions();
const pan = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current;
const scale = useRef(new Animated.Value(1)).current;
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderMove: (event, gestureState) => {
// More accurate than gestureState.numberActiveTouches
// https://github.com/facebook/react-native/blob/8a31dfe567a22dbc018ea763b0a9706068276c4a/Libraries/Interaction/PanResponder.js#L383-L384
const activeTouches = event.nativeEvent.changedTouches.length;
if (activeTouches === 1) {
pan.setValue({
x: gestureState.dx,
y: gestureState.dy,
});
} else if (activeTouches >= 2) {
const touches = event.nativeEvent.changedTouches;
const touchA = touches[0];
const touchB = touches[1];
const distance = pointsDistance(
[touchA.pageX, touchA.pageY],
[touchB.pageX, touchB.pageY]
);
const screenMovedPercents = distance / dimensions.width;
scale.setValue(1 + screenMovedPercents * 3);
}
},
onPanResponderRelease: () => {
Animated.parallel([
Animated.spring(pan, {
toValue: {
x: 0,
y: 0,
},
useNativeDriver: true,
}),
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
}),
]).start();
},
})
).current;
return (
<Animated.Image
{...panResponder.panHandlers}
source={{ uri: IMAGE_URI }}
style={{
height: 200,
width: '90%',
borderRadius: 10,
transform: [
// or pan.getTranslateTransform()
{ translateX: pan.x },
{ translateY: pan.y },
{ scale },
],
}}
/>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment