Last active
August 9, 2023 07:38
-
-
Save mcousillas6/1a4864cd6c008bed8fb0450726d8a191 to your computer and use it in GitHub Desktop.
react-native-gesture-handler + react-native-reanimate example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useMemo, useRef } from 'react'; | |
import { View } from 'react-native'; | |
import { node } from 'prop-types'; | |
import { PanGestureHandler, State, PinchGestureHandler } from 'react-native-gesture-handler'; | |
import Animated from 'react-native-reanimated'; | |
import styles from './styles'; | |
/** styles.js | |
import { StyleSheet } from 'react-native'; | |
export default StyleSheet.create({ | |
container: { | |
flex: 1, | |
justifyContent: 'center', | |
alignItems: 'center', | |
backgroundColor: '#F5FCFF', | |
}, | |
box: { | |
width: 50, | |
height: 50, | |
margin: 20, | |
backgroundColor: 'red', | |
}, | |
}); | |
*/ | |
const { add, set, block, cond, eq, multiply, max, concat } = Animated; | |
const usePan = () => { | |
const offsetX = useRef(new Animated.Value(0)).current; | |
const offsetY = useRef(new Animated.Value(0)).current; | |
const transX = useRef(new Animated.Value(0)).current; | |
const transY = useRef(new Animated.Value(0)).current; | |
const handlePan = useMemo(() => { | |
return Animated.event([ | |
{ | |
nativeEvent: ({ translationX: x, translationY: y, state }) => | |
block([ | |
set(transX, add(offsetX, x)), | |
set(transY, add(offsetY, y)), | |
cond(eq(state, State.END), [ | |
set(offsetX, add(offsetX, x)), | |
set(offsetY, add(offsetY, y)), | |
]), | |
]), | |
}, | |
]); | |
}, [offsetX, offsetY, transX, transY]); | |
return { offsetX, offsetY, transX, transY, handlePan }; | |
}; | |
const PanView = ({ children, ...props }) => { | |
const { transX, transY, handlePan } = usePan(); | |
return ( | |
<PanGestureHandler onGestureEvent={handlePan} onHandlerStateChange={handlePan} {...props}> | |
<Animated.View style={{ transform: [{ translateX: transX, translateY: transY }] }}> | |
{children} | |
</Animated.View> | |
</PanGestureHandler> | |
); | |
}; | |
PanView.propTypes = { | |
children: node, | |
}; | |
const usePinch = () => { | |
const zoom = useRef(new Animated.Value(1)).current; | |
const offset = useRef(new Animated.Value(1)).current; | |
const handlePinch = useMemo(() => { | |
return Animated.event([ | |
{ | |
nativeEvent: ({ scale, state }) => | |
block([ | |
cond(eq(state, State.ACTIVE), set(zoom, max(multiply(offset, scale), 1))), | |
cond(eq(state, State.END), [set(offset, max(multiply(offset, scale), 1))]), | |
]), | |
}, | |
]); | |
}, [offset, zoom]); | |
return { scale: zoom, offset, handlePinch }; | |
}; | |
const PinchView = ({ children, ...props }) => { | |
const { scale: zoom, handlePinch } = usePinch(); | |
return ( | |
<PinchGestureHandler onGestureEvent={handlePinch} onHandlerStateChange={handlePinch} {...props}> | |
<Animated.View style={{ transform: [{ scale: zoom }] }}>{children}</Animated.View> | |
</PinchGestureHandler> | |
); | |
}; | |
PinchView.propTypes = { | |
children: node, | |
}; | |
const useRotate = () => { | |
const rotationValue = useRef(new Animated.Value(0)).current; | |
const offset = useRef(new Animated.Value(0)).current; | |
const handleRotate = useMemo(() => { | |
return Animated.event([ | |
{ | |
nativeEvent: ({ rotation, state }) => | |
block([ | |
set(rotationValue, add(rotation, offset)), | |
cond(eq(state, State.END), [set(offset, add(rotation, offset))]), | |
]), | |
}, | |
]); | |
}, [offset, rotationValue]); | |
return { rotation: rotationValue, offset, handleRotate }; | |
}; | |
const RotateView = ({ children, ...props }) => { | |
const { rotation, handleRotate } = useRotate(); | |
return ( | |
<RotationGestureHandler | |
onGestureEvent={handleRotate} | |
onHandlerStateChange={handleRotate} | |
{...props}> | |
<Animated.View style={{ transform: [{ rotate: concat(rotation, 'rad') }] }}> | |
{children} | |
</Animated.View> | |
</RotationGestureHandler> | |
); | |
}; | |
PinchView.propTypes = { | |
children: node, | |
}; | |
const Sandbox = () => { | |
const panRef = useRef(); | |
const pinchRef = useRef(); | |
const rotateRef = useRef(); | |
return ( | |
<View style={styles.container}> | |
<PanView ref={panRef} simultaneousHandlers={[pinchRef, rotateRef]}> | |
<PinchView ref={pinchRef} simultaneousHandlers={[panRef, rotateRef]}> | |
<RotateView ref={rotateRef} simultaneousHandlers={[pinchRef, panRef]}> | |
<View style={styles.box} /> | |
</RotateView> | |
</PinchView> | |
</PanView> | |
</View> | |
); | |
}; | |
export default Sandbox; |
Pich is not working please help me ? I need to use pichGesture and panGesture
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is very useful, thanks for sharing! Minor enhancement; I believe for
simultaneousHandlers
to work you need toforwardRef
your functional components. 🙏