react-native: [Android] RefreshControl gesture conflicts with horizontal ScrollView gesture

Description

I have a use case where I want to list horizontally cards. I implemented it with a horizontal ScrollView.

Then, for each card I want to implement the pull-to-refresh pattern to let the user manually refresh the data displayed in there.

I nested therefore a ScrollView within the first one but this time with a RefreshControl component as advised by @ericvicenti in https://github.com/facebook/react-native/issues/10910#issuecomment-260471144 .

The issue is that on Android, when I do pull-to-refresh gesture, the refresh component gets in conflict with the horizontal ScrollView (see gif below).

scrollview-refreshcontrol-android

Reproduction

https://rnplay.org/apps/dZSmGQ

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isRefreshing: false};
  }

  _onRefresh() {
    this.setState({isRefreshing: true});
    setTimeout(() => {
      this.setState({isRefreshing: false});
    }, 2000);
  }

  render() {
    return (
      <View style={{flex: 1}}>
        <Text style={{padding: 20}}>
      		Text
        </Text>
        <ScrollView
          contentContainerStyle={styles.container}
          horizontal
          pagingEnabled
          showsHorizontalScrollIndicator={false}
          directionalLockEnabled
        >
          <ScrollView
            refreshControl={
              <RefreshControl
                refreshing={this.state.isRefreshing}
                onRefresh={this._onRefresh.bind(this)}
              />
            }>
              <Text style={styles.card}>First child</Text>
          </ScrollView>
          <ScrollView
            refreshControl={
              <RefreshControl
                refreshing={this.state.isRefreshing}
                onRefresh={this._onRefresh.bind(this)}
              />
            }>
              <Text style={styles.card}>Second child</Text>
          </ScrollView>
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  card: {
    width: Dimensions.get('window').width,
    textAlign: 'center'
  },
  container: {
    borderWidth: 1,
    borderColor: 'red'
  },
  refreshControl: {
    backgroundColor: 'red'
  }
});

Solution

  • Find out why the pull-to-refresh and horizontal scrollview gestures are conflicting
  • Isolate the horizontal gesture for the horizontal scrollview
  • Isolate the vertical gesture for the RefreshControl component

Additional Information

  • React Native version: 0.42
  • Platform: Android
  • Operating System: MacOS

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 23
  • Comments: 35 (1 by maintainers)

Most upvoted comments

This happens on RN 0.48.2 as well. I hope this could be reopened because it makes pull to refresh extremely difficult to do on Android.

I am having the same issue on 0.41-rc.0. I think a possible fix might be to disable horizontal scroll while doing vertical scroll. I think this might be because touch event just gets hijacked by horizontal ScrollView.

Update: RefreshControl component could use onPullStart and onPullEnd this way horizontal scrolling could be disabled.

This is really critical bug because it blocks to use whole component on Android (with usage of pull-to-refresh pattern). Please fix ASAP. Thanks.

I just checked if the issue was still there when using newest version of RN. And… it looks better in 0.44 🎉

Now, when doing the same gesture (vertical+horizontal), the swipe refresh is invalidated - where before the swipe refresh component remained stuck on the screen.

Demo https://github.com/fdnhkj/rn-issue-11939 scrollview-refreshcontrol-android

I’ll read the release notes to see which commit helped.

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we’re automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@rexjrs @zhuyifan2013 Being part of RN community for some while, I must say Android usually gets neglected. I created a post on Product Pains for this issue.

https://react-native.canny.io/feature-requests/p/android-refreshcontrol-gesture-conflicts-with-horizontal-scrollview-gesture

Bumping. Any updates on this? Really need a fix.

January 17 this was posted and still no update? Seriously?

@diesmori this technique works fine. @ahmad2smile you should take cake of you own child listview .

I solved it calling to _onRefresh() on a parent component:

Scrollable component: render() { return ( <Container> <Content> <ScrollView //without refreshControl .../> </Content> </Container> ...etc

Parent component: <ScrollView refreshControl={ <RefreshControl refreshing={this.state.refreshing} onRefresh={this._onRefresh.bind(this)} /> } > <Tasks ... /> </ScrollView>

I have Swipe elements into Task controller