Nested PinchGestureHandler & PanGestureHandler not working in Android
See original GitHub issueI am completely confused on why this code would work on iOS but not on Android. My react-native-gesture-handler setup is working because I have another PanGestureHandler working as expected.
/*********************** Imports ***********************/
import React, { useRef, useEffect } from 'react';
import {
View, StyleSheet, Animated,
} from 'react-native';
import ZoomImage from './ZoomableImage';
import { vw, vh, isiPhoneX } from '../Styles/StyleUtils';
/********************* End Imports *********************/
/*********************** ImageView Function ***********************/
const ImageView = ({ dismiss, uri, imageLayout }) => {
const animation = useRef(new Animated.Value(0));
useEffect(() => {
Animated.timing(animation.current, {
toValue: 1,
duration: 250,
}).start();
}, []);
function closeImage() {
Animated.timing(animation.current, {
toValue: 0,
duration: 250,
}).start(() => dismiss());
}
return (
<View style={styles.mainContainer}>
<Animated.View style={[
styles.container,
{
backgroundColor: animation.current.interpolate({
inputRange: [0, 1],
outputRange: ["rgba(0, 0, 0, 0)", "rgba(0, 0, 0, 0.5)"],
})
}
]}>
{/* <View style={styles.header}>
<TouchableOpacity style={styles.closeBtn} onPress={closeImage}>
<Icon name="close" color={blackColor} size={30} />
</TouchableOpacity>
</View> */}
<ZoomImage dismiss={closeImage} imageStyle={[
{
left: animation.current.interpolate({
inputRange: [0, 1],
outputRange: [imageLayout.pageX, 0] // 0 : 150, 0.5 : 75, 1 : 0
}),
top: animation.current.interpolate({
inputRange: [0, 1],
outputRange: [imageLayout.pageY, vh(24)] // 0 : 150, 0.5 : 75, 1 : 0
}),
width: animation.current.interpolate({
inputRange: [0, 1],
outputRange: [imageLayout.width, vw(100)],
}),
height: animation.current.interpolate({
inputRange: [0, 1],
outputRange: [imageLayout.height, vw(100)],
})
}
]}
source={{ uri: uri }} />
</Animated.View>
</View>
);
};
/********************** End ImageView Function *******************/
export default ImageView;
const styles = StyleSheet.create({
header: {
marginTop: isiPhoneX() ? 40 : 25,
alignItems: "flex-end"
},
closeBtn: {
paddingHorizontal: 20,
},
mainContainer: {
position: "absolute",
width: vw(100),
height: vh(100)
},
container: {
position: "absolute",
top: 0,
left: 0,
right: 0, bottom: 0,
},
image: {
position: "absolute",
}
});
/*********************** Imports ***********************/
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { Animated } from 'react-native';
import {
State,
PanGestureHandler,
PinchGestureHandler
} from 'react-native-gesture-handler';
import { vw, vh } from '../Styles/StyleUtils';
/********************* End Imports *********************/
/*********************** ZoomableImage Function ***********************/
const ZoomableImage = (props) => {
const panRef = useRef();
const pinchRef = useRef();
const closeAnimation = useRef(new Animated.ValueXY({ x: 0, y: 0 }));
const scaleAnimation = useRef(new Animated.Value(1));
const baseScale = useRef(new Animated.Value(1));
const scale = useRef(Animated.multiply(baseScale.current, scaleAnimation.current));
const [lastScale, setLastScale] = useState(1);
useEffect(() => {
console.log('Refs', panRef);
}, [panRef.current]);
const onPanHandlerGesture = useCallback(({ nativeEvent }) => {
console.log('Native Event', nativeEvent);
closeAnimation.current.setValue({
x: nativeEvent.translationX,
y: nativeEvent.translationY
});
}, []);
const onPanHandlerStateChange = useCallback(({ nativeEvent }) => {
console.log('New Pan Event', nativeEvent);
if (nativeEvent.oldState === State.ACTIVE) {
if (
nativeEvent.translationY > 250
|| nativeEvent.velocityY > 1200
) {
Animated.parallel([
Animated.timing(scaleAnimation.current, {
toValue: 1,
duration: 200
}),
Animated.timing(baseScale.current, {
toValue: 1,
duration: 200
}),
Animated.timing(closeAnimation.current, {
toValue: { x: 0, y: 0 },
duration: 200
})
]).start(() => props.dismiss());
}
else {
Animated.timing(closeAnimation.current, {
toValue: { x: 0, y: 0 },
duration: 100
}).start();
}
}
}, [lastScale]);
const onPinchGestureEvent = Animated.event([{ nativeEvent: { scale: scaleAnimation.current } }]);
useCallback(({ nativeEvent }) => {
scaleAnimation.current.setValue(nativeEvent.scale);
}, [lastScale]);
const onPinchHandlerStateChange = ({ nativeEvent }) => {
console.log('New Pinch Event', nativeEvent);
if (nativeEvent.oldState === State.ACTIVE) {
const newLastScale = lastScale * nativeEvent.scale;
setLastScale(newLastScale);
baseScale.current.setValue(newLastScale);
scaleAnimation.current.setValue(1);
}
};
return (
<PanGestureHandler maxPointers={2} avgTouches onHandlerStateChange={onPanHandlerStateChange}
minDist={10} onGestureEvent={onPanHandlerGesture} ref={panRef}>
<PinchGestureHandler ref={pinchRef} simultaneousHandlers={panRef}
onHandlerStateChange={onPinchHandlerStateChange} onGestureEvent={onPinchGestureEvent}>
<Animated.Image style={[
props.imageStyle,
{
transform: [
{ perspective: 1000 },
{
translateY: closeAnimation.current.y.interpolate({
inputRange: [-vh(25), vh(25)],
outputRange: [-vh(25), vh(25)],
extrapolate: "clamp"
})
},
{
translateX: closeAnimation.current.x.interpolate({
inputRange: [-vw(25), vw(25)],
outputRange: [-vw(10), vw(10)],
extrapolate: "clamp"
})
},
{
scale: scale.current.interpolate({
inputRange: [1, 2.5],
outputRange: [1, 2.5],
extrapolate: "clamp"
})
}
]
}
]} source={props.source} />
</PinchGestureHandler>
</PanGestureHandler>
);
};
ZoomableImage.defaultProps = {
imageStyle: {},
source: { uri: "" }
};
/********************** End ZoomableImage Function *******************/
export default ZoomableImage;
Issue Analytics
- State:
- Created 4 years ago
- Reactions:3
- Comments:9 (1 by maintainers)
Top Results From Across the Web
PinchGestureHandler not working on android - Stack Overflow
i have an android device, and it is not working, dont know why please help!!!!! beside this PanGestureHandler working perfectly.
Read more >About Gesture Handlers | React Native ... - Software Mansion
When one gesture becomes active, it cancels all the other gestures (read more ... Gesture handler components do not instantiate a native view...
Read more >Using the Gesture Handler in React Native | by SaidHayani
PanGestureHandler is a container or wrapper we can use to wrap a component (EX: View `) to handle and track the gesture movements...
Read more >React-Native Pinchgesturehandler Doesn't Work - ADocLib
PanGestureHandler doesn't work on Android 5.11.11; ... In my screen I try to use nested gestures PanRotatePinch but it is not working If...
Read more >[QUESTION] PinchGestureHandler transformOrigin problem ...
You could also use a PanGestureHandler in order to figure out the position of your gesture inside the image.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

@thevishnupradeep @orcunorcun @Hirbod I think I found a solution. Try adding minPointers and maxPointers to the pan and pinch gesture handlers like this:
I think this is saying that you pan with 1 finger, and pinch with 2.
Every handler should have it’s own
Animated.Viewas a child, like @emclab said. This is related to the way how we internally pass callbacks inside handlers, I’ll check out if this is fixable. Closing because it doesn’t have the proper smallest possible repro example.