I'm trying to implement multi-touch slider functionality (based on the example code provided by React Native Gesture Handler).
I'm finding that when I create two TapOrPan
components, they work fine individually but the slider state is shared when touching both sliders at the same time.
Why this is happening, given that I'm using two separate components? What am I missing?
Expo link for debugging: https://snack.expo.io/aPLAoFWar
import React, { Component } from 'react';
import { Animated, Dimensions, StyleSheet, Text, View } from 'react-native';
import {
PanGestureHandler,
TapGestureHandler,
ScrollView,
State,
} from 'react-native-gesture-handler';
export function TapOrPan({width, radius}) {
const tapRef = React.createRef();
const panRef = React.createRef();
const _id = parseInt(Math.random() * 100);
const _touchX = new Animated.Value(width / 2 - radius);
const _circleValue = new Animated.Value(-radius);
const _translateX = Animated.add(_touchX, _circleValue);
const _onPanGestureEvent = Animated.event(
[{nativeEvent: {x: _touchX}}],
{useNativeDriver: true}
);
const styles = StyleSheet.create({
horizontalPan: {
backgroundColor: '#777',
height: 120,
justifyContent: 'center',
marginVertical: 10,
},
circle: {
backgroundColor: '#fff',
borderRadius: radius,
height: radius * 2,
width: radius * 2,
},
wrapper: {
flex: 1,
},
});
function _onTapHandlerStateChange({ nativeEvent }) {
console.log(_id.toString() + ": " + JSON.stringify(nativeEvent));
if (nativeEvent.oldState === State.ACTIVE) {
// Once tap happened we set the position of the circle under the tapped spot
_touchX.setValue(nativeEvent.x);
}
}
return (
<TapGestureHandler
ref={tapRef}
onHandlerStateChange={_onTapHandlerStateChange}
>
<Animated.View style={styles.wrapper}>
<PanGestureHandler
ref={panRef}
activeOffsetX={[0, 0]}
onGestureEvent={_onPanGestureEvent}
>
<Animated.View style={styles.horizontalPan}>
<Animated.View
style={[
styles.circle,
{transform: [{translateX: _translateX}]},
]}
/>
</Animated.View>
</PanGestureHandler>
</Animated.View>
</TapGestureHandler>
);
}
export default function Example() {
const windowWidth = Dimensions.get('window').width;
return (
<ScrollView>
<TapOrPan width={windowWidth} radius={30} />
<TapOrPan width={windowWidth} radius={30} />
</ScrollView>
);
}
If think that it will not work as you want. There is no two coordinates for two different fingers with different directions moving. There is one coordinates of some point, that is calculated from all of your finger's coordinates (different at different platforms). https://github.com/software-mansion/react-native-gesture-handler/blob/d3c8ff130e7d925dae7cec149098c5d042a00120/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.java#L44