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

Created on 17 Jan 2017  路  35Comments  路  Source: facebook/react-native

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
Android Ran Commands Stale

Most helpful comment

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.

All 35 comments

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.

Is there any workaround right now?

@sohobloo Not as far as I know. I struggled with this a lot and went back to ViewPagerAndroid. Unfortunately, iOS issues get a bit more love and attention than Android ones.

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

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.

Any update ???? Developer ???

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

@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

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.

@fdnhkj Haven't developed in RN for a while, but was wondering if slight gesture changes would cancel swipe. What I mean is - would slight (natural) gesture changes cancel out PullToRefresh? Would this be frustrating to end user?

Still, I think this is not ideal. The underlying problem is that gesture is being hijacked. Progress on PTR element should remain, even if you move horizontally, since this is the expected interaction from users.

TabNavigation + FlatList in RN 0.44 works well (PullToRefresh and swipe left and right), maybe you could refer to that implementation.

+1, Needs fix asap

Yep, I thought it was something I had done, but nope, just a bug, are there any news or workaround other than upgrading RN ?

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.

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.

Happens in 0.50.2 too. Could this be reopened, @hramos ?

Same for me. I vote for reopening the issue.

Same for me.I'm using the newest version, 0.50.3. It's a bug from 2017 to 2018.

Seems it was fixed, I do not have the problem anymore since 0.52

Just upgraded to react-native: 0.52.2 but the problem still occurs.

Strange... it disappeared completely in my app, ios and android. My setup is: listviews with refresh control nested in tabs.

Btw my tabs are from react-native-scrollable-tabview, maybe I updated it, can't remember. The rest of my navigation is react-native-navigation. This I changed recently, I was using react-native-router-flix before, but rn-navigation is not handling my tabs

Same problem on react-native: 0.52.2

The issue was 1 swipe event was being handled by 2 Listeners. Child and Parent. I moved Pull-to-Refresh event setup to Parent and running control of child in parent. As sort of suggested by @badaz

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

+1

@diesmori I thought this technique would work but it sort of doesn't. If your child has the Vertical List and then you put refresh control on you parent which is Horizontal then you can't Scroll Up the Child List. It just triggers refresh on Horizontal Parent List.

This definitely needs a fix, nearly impossible to refresh on Android. Any progress on this issue?

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

@ahmad2smile I mean that you could disable refreshControl of the Horizontal when you scroll your child FlatList by FlatList onScroll callback. Any comment appreciate.

I tried that @yeshengwu . The Refresh Controls don't update dynamically. If its disabled it doesn't update onScroll.

I ended up keep my setup on iOS as it works smooth on iOS but on Android I had to remove Parent list and ended up with Detecting Left Right Swipe Gestures and rendering new elements in place on Parent List. Its horrible but that was the only option on android.

+1

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

Was this page helpful?
0 / 5 - 0 ratings