I just tried importing the example code for rotate+scale into my TypeScript+Expo app for experimentation, but I met a strange problem. On my app, I can only do either rotate or scale when gesturing with two touches, but not both at the same time. However, if I try the code in a snack, it works fine doing both at the same time.
none of which, to my knowledge, should make any difference. Do you have any idea what's going wrong?
Also, bonus question: There's a PanResponder that supposedly should do "tilting", but I'm not sure if that's working on either example? What should it do, and how? I can't seem to do anything but rotate or scale, with neither two or one touch.
import * as React from 'react';
import { Animated, StyleSheet, View } from 'react-native';
import {
PanGestureHandler,
PinchGestureHandler,
RotationGestureHandler,
ScrollView,
State,
} from 'react-native-gesture-handler';
const USE_NATIVE_DRIVER = false; // https://github.com/kmagiera/react-native-gesture-handler/issues/71
export class Sticker extends React.Component {
onTiltGestureEvent: (...args: any[]) => void;
lastTilt: number;
tiltStr: Animated.AnimatedInterpolation;
tilt: Animated.Value;
onRotateGestureEvent: (...args: any[]) => void;
lastRotate: number;
rotateStr: Animated.AnimatedInterpolation;
rotate: Animated.Value;
onPinchGestureEvent: (...args: any[]) => void;
lastScale: number;
scale: Animated.AnimatedMultiplication;
pinchScale: Animated.Value;
baseScale: Animated.Value;
constructor(props) {
super(props);
/* Pinching */
this.baseScale = new Animated.Value(1);
this.pinchScale = new Animated.Value(1);
this.scale = Animated.multiply(this.baseScale, this.pinchScale);
this.lastScale = 1;
this.onPinchGestureEvent = Animated.event(
[{ nativeEvent: { scale: this.pinchScale } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
/* Rotation */
this.rotate = new Animated.Value(0);
this.rotateStr = this.rotate.interpolate({
inputRange: [-100, 100],
outputRange: ['-100rad', '100rad'],
});
this.lastRotate = 0;
this.onRotateGestureEvent = Animated.event(
[{ nativeEvent: { rotation: this.rotate } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
/* Tilt */
this.tilt = new Animated.Value(0);
this.tiltStr = this.tilt.interpolate({
inputRange: [-501, -500, 0, 1],
outputRange: ['1rad', '1rad', '0rad', '0rad'],
});
this.lastTilt = 0;
this.onTiltGestureEvent = Animated.event(
[{ nativeEvent: { translationY: this.tilt } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
}
onRotateHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this.lastRotate += event.nativeEvent.rotation;
this.rotate.setOffset(this.lastRotate);
this.rotate.setValue(0);
}
};
onPinchHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this.lastScale *= event.nativeEvent.scale;
this.baseScale.setValue(this.lastScale);
this.pinchScale.setValue(1);
}
};
onTiltGestureStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this.lastTilt += event.nativeEvent.translationY;
this.tilt.setOffset(this.lastTilt);
this.tilt.setValue(0);
}
};
render() {
return (
<PanGestureHandler
id="image_tilt"
onGestureEvent={this.onTiltGestureEvent}
onHandlerStateChange={this.onTiltGestureStateChange}
minDist={10}
minPointers={2}
maxPointers={2}
avgTouches={true}
>
<RotationGestureHandler
id="image_rotation"
simultaneousHandlers="image_pinch"
onGestureEvent={this.onRotateGestureEvent}
onHandlerStateChange={this.onRotateHandlerStateChange}
>
<PinchGestureHandler
id="image_pinch"
simultaneousHandlers="image_rotation"
onGestureEvent={this.onPinchGestureEvent}
onHandlerStateChange={this.onPinchHandlerStateChange}
>
<View style={styles.container} collapsable={false}>
<Animated.Image
style={[
styles.pinchableImage,
{
transform: [
{ perspective: 200 },
{ scale: this.scale },
{ rotate: this.rotateStr },
{ rotateX: this.tiltStr },
],
},
]}
source={{
uri: 'https://avatars1.githubusercontent.com/u/6952717',
}}
/>
</View>
</PinchGestureHandler>
</RotationGestureHandler>
</PanGestureHandler>
);
}
}
export default Sticker;
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'black',
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
},
pinchableImage: {
width: 250,
height: 250,
},
});