Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React Native Touch & Gesture

React Native Touch & Gesture

React Native allows for building great native apps by utilising native mobile components. Apparently handling touch and gestures is quite tricky as it often needs to interact with the application code which runs asynchronously in the javascript VM. This talk is going to be about how the gesture system has been designed and implemented in React Native and how to use it to stay out of trouble.

Krzysztof Magiera

April 21, 2017
Tweet

More Decks by Krzysztof Magiera

Other Decks in Programming

Transcript

  1. TOUCHABLE <TouchableHighlight onPress={() => console.log('!!')}/> <TouchableOpacity onPress={() => console.log('!!')}/> <TouchableWithoutFeedback

    onPress={() => console.log('!!')}/> <TouchableNativeFeedback onPress={() => console.log('!!')}/>
  2. JS RESPONDER SYSTEM TOUCH DOWN TOUCH MOVE TOUCH MOVE TOUCH

    MOVE TOUCH UP JS Thread UI Thread <View/> <Touchable/> <View/> <View/> <Touchable/> <Touchable/> <Touchable/>
  3. JS RESPONDER SYSTEM TOUCH DOWN TOUCH MOVE TOUCH MOVE TOUCH

    MOVE TOUCH UP JS Thread UI Thread <View/> <Touchable/> <View/> <View/> <Touchable/> <Touchable/> <Touchable/>
  4. JS RESPONDER SYSTEM onStartShouldSetResponder onMoveShouldSetResponder Become a responder onResponderGrant onResponderReject

    onResponderMove onResponderRelease https://facebook.github.io/react-native/docs/gesture-responder-system.html
  5. COLLAPSABLE HEADERS const yOffset = new Animated.Value(0) const translateY =

    yOffset.interpolate({ inputRange: [0, IMG_HEIGHT - NAVBAR_HEIGHT, IMG_HEIGHT], outputRange: [0, 0, NAVBAR_HEIGHT], })
  6. COLLAPSABLE HEADERS const yOffset = new Animated.Value(0) const scale =

    yOffset.interpolate({ inputRange: [-IMG_HEIGHT, 0, 1], outputRange: [2, 1, 1], }) https://gist.github.com/kmagiera/883c991e613de681e137dd01a25ae58f
  7. COLLAPSABLE HEADERS const yOffset = new Animated.Value(0) const scale =

    yOffset.interpolate({ inputRange: [-IMG_HEIGHT, 0, 1], outputRange: [2, 1, 1], }) const translateY = yOffset.interpolate({ inputRange: [-2, 0, IMG_HEIGHT - NAVBAR_HEIGHT, IMG_HEIGHT], outputRange: [-1, 0, 0, NAVBAR_HEIGHT], }) https://gist.github.com/kmagiera/883c991e613de681e137dd01a25ae58f
  8. COLLAPSABLE HEADERS const yOffset = new Animated.Value(0) const scale =

    yOffset.interpolate({ inputRange: [-IMG_HEIGHT, 0, 1], outputRange: [2, 1, 1], }) const translateY = yOffset.interpolate({ inputRange: [-2, 0, IMG_HEIGHT - NAVBAR_HEIGHT, IMG_HEIGHT], outputRange: [-1, 0, 0, NAVBAR_HEIGHT], }) animatedHeaderStyles = { transform: [{ translateY }, { scale }] } onScrollHandler = Animated.event( [{ nativeEvent: { contentOffset: { y: yOffset } } }], { useNativeDriver: true } ) <Animated.ScrollView onScroll={onScrollHandler}> ... <Animated.Image style={[styles.header, animatedHeaderStyles]} source={IMG_SRC} /> </Animated.ScrollView>
  9. Problem #2 Lack of an API that would allow for

    defining interactions between native gesture recognizers
  10. NATIVE DRIVER const translateX = new Animated.Value(0) const translateY =

    new Animated.Value(0) const moveEvent = Animated.event( [{}, { dx: translateX, dy: translateY }], ) const animatedStyles = { transform: [ { translateX }, { translateY }, ] } const panResponder = PanResponder.create({ ... onPanResponderMove: moveEvent, onPanResponderRelease: handlePanResponderEnd, })
  11. NATIVE DRIVER const handlePanResponderEnd = (e, gestureState) => { //

    Merge value and offset for each animated node and // then store it under offset keeping value set // to 0 and ready for next pan move events translateX.flattenOffset() translateX.extractOffset() translateY.flattenOffset() translateY.extractOffset() } <Animated.View style={[styles.circle, animatedStyles]} {...panResponder.panHandlers} > <Image source={IMG_SRC} style={styles.image} /> </Animated.View>
  12. INTERACTABLE https://github.com/wix/react-native-interactable • Supports pan gesture recognition in native •

    Works with Animated Native Driver • Provides very easy to use API for building spring-based interactions
  13. GESTURE HANDLER https://github.com/kmagiera/react-native-gesture-handler <TapGestureHandler /> <PanGestureHandler /> <LongPressGestureHandler /> <NativeViewGestureHandler

    /> Components States UNDETERMINED FAILED BEGAN CANCELLED ACTIVE END Handlers onHandlerStateChange onGestureEvent Animated Native Driver Approved
  14. GESTURE HANDLERS INTERACTION DOWN, MOVE, MOVE, MOVE, UP DOWN, MOVE,

    MOVE, MOVE, UP Single Tap Double Tap ! DOWN, MOVE, MOVE, MOVE, MOVE, UP !
  15. GESTURE HANDLERS INTERACTION DOWN, MOVE, MOVE, MOVE, UP DOWN, MOVE,

    MOVE, MOVE, UP Single Tap Double Tap ! DOWN, MOVE, MOVE, MOVE, MOVE, UP !
  16. render() { return ( <LongPressGestureHandler minDurationMs={2000}> <TapGestureHandler shouldCancelWhenOutside={true}> <PanGestureHandler minDeltaX={50}>

    <Animated.View style={...}/> </PanGestureHandler> </TapGestureHandler> </LongPressGestureHandler> ) } GESTURE HANDLER