React Native - Pan Responder inside of a ScrollView

Lets talk PanResponder in a ScrollView. This gets brought up frequently, so lets address it.

Scenario

You’ve got a PanResponder in your ScrollView. When you scroll you want it to scroll, when you interact with the component with the PanResponder you want it to do PanResponder things.

What happens

Things start scrolling just fine. You attemp to drag, all goes swimmingly, then the ScrollView scrolls, your drag stops working and it just sits there stuck until you go re-interact with it. Yikes. You curse the react native gods and begrudgingly start learning Objective-C.

Janky

Solution

The magic solution is scrollEnabled={false}. That’s it. Seriously. Sadly it’s only supported on ios as of me writing this blog post. I’m sure it’ll be supported in the future for android.

Done

Play with it here https://rnplay.org/apps/we3HnA

Full Code Here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  PanResponder,
  ScrollView,
  View,
  Animated,
  Text
} = React;

var SampleApp = React.createClass({
  getInitialState: function() {
        return {
      scroll: true,
      pan: new Animated.ValueXY()
    }
  },
  componentWillMount: function() {
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onPanResponderGrant: () => this.setState({scroll: false}),
      onPanResponderMove: Animated.event([null, {dx: this.state.pan.x, dy: this.state.pan.y}]),
        onPanResponderRelease: () => this.setState({scroll: true})
    })
  },
  render: function() {
    return (
      <View style={styles.container}>
                <ScrollView 
            style={{flex: 1}}
          scrollEnabled={this.state.scroll}                      
        >
            <Animated.View 
                style={{transform: this.state.pan.getTranslateTransform(), position: 'absolute', left: 150, top: 150}}
                {...this._panResponder.panHandlers}
            >
                <Text>Drag Me</Text>
            </Animated.View>
        </ScrollView>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,

  },
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);
Tagged under panresponder, react-native, scrollview

Comments