React-native-pager-view: [V2] Disable content touches when ViewPager is scrolling on iOS

Created on 10 Oct 2019  路  6Comments  路  Source: callstack/react-native-pager-view

Bug

On Android when ViewPager is scrolling with swipe gesture all content(including all Touchables) are disabled. On iOS it's not - all touchables are interactable while swiping so when viewpager content has button or other clickable components they are clicked.

I tried to fix it with setUserInteractioEnabled and with UIGestureRecognizer, but haven't come up with any idea how to fix. Problem is to cancel all currently tapped touchables events when scroll begins.

Environment info

React native info output:

info
  React Native Environment Info:
    System:
      OS: macOS 10.15
      CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
      Memory: 1.36 GB / 16.00 GB
      Shell: 5.7.1 - /bin/zsh
    Binaries:
      Node: 10.16.3 - /usr/local/bin/node
      Yarn: 1.19.0 - /usr/local/bin/yarn
      npm: 6.11.3 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 13.0, DriverKit 19.0, macOS 10.15, tvOS 13.0, watchOS 6.0
      Android SDK:
        API Levels: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 7, 8, 9
        Build Tools: 27.0.3, 28.0.2, 28.0.3, 29.0.2
        System Images: android-16 | Intel x86 Atom, android-18 | Google APIs Intel x86 Atom, android-19 | Google APIs Intel x86 Atom, android-21 | Intel x86 Atom, android-22 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-24 | Google Play Intel x86 Atom, android-27 | Google APIs Intel x86 Atom, android-28 | Android TV Intel x86 Atom, android-28 | Google Play Intel x86 Atom
    IDEs:
      Android Studio: 3.5 AI-191.8026.42.35.5900203
      Xcode: 11.0/11A420a - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.6 => 16.8.6
      react-native: 0.59.10 => 0.59.10
    npmGlobalPackages:
      react-native-cli: 2.0.1
      react-native-git-upgrade: 0.2.7
      react-native-rename: 2.4.1

Library version: 2.0.1

Steps To Reproduce

Use ViewPager on iOS with any touchable components inside

bug ios

Most helpful comment

I add onMoveShouldSetResponderCapture method to ViewPager to prevent the touch event pass to the child view when viewpager is scrolling:

    onPageScroll(evt) {
        this.setState({pageScrolling: true});
    }

    onPageScrollStateChanged(evt) {
        if ('idle' == evt.nativeEvent.pageScrollState) {
            this.setState({pageScrolling: false});
        } else {
            this.setState({pageScrolling: true});
        }
    }

    moveShouldSetResponderCapture(evt) {
        return this.state.pageScrolling;
    }

    render() {
        return (
                <ViewPager style={styles.viewPager}
                    initialPage={0}
                    scrollEnabled={this.state.scrollEnabled}
                    onPageSelected={this.onPageSelected}
                    orientation="horizontal"
                    transitionStyle="scroll"
                    showPageIndicator={false}
                    animationsAreEnabled={animationsAreEnabled}
                    onPageScroll={(evt) => this.onPageScroll(evt)}
                    onPageScrollStateChanged={(evt) => this.onPageScrollStateChanged(evt)}
                    onMoveShouldSetResponderCapture={(evt) => this.moveShouldSetResponderCapture(evt)}
                    ref={this.viewPager}
                >
                    {pages.map(p => this.renderPage(p))}
                </ViewPager>
        )
    }

All 6 comments

Hey,
you can use onPageScrollStateChanged method, to block button interaction.

switch(pageScrollState){
case "idle": enableButton();
default: disableButton(); 
}

Hey,
you can use onPageScrollStateChanged method, to block button interaction.

switch(pageScrollState){
case "idle": enableButton();
default: disableButton(); 
}

i dont think this is a good solution...

Any fix ?

I add onMoveShouldSetResponderCapture method to ViewPager to prevent the touch event pass to the child view when viewpager is scrolling:

    onPageScroll(evt) {
        this.setState({pageScrolling: true});
    }

    onPageScrollStateChanged(evt) {
        if ('idle' == evt.nativeEvent.pageScrollState) {
            this.setState({pageScrolling: false});
        } else {
            this.setState({pageScrolling: true});
        }
    }

    moveShouldSetResponderCapture(evt) {
        return this.state.pageScrolling;
    }

    render() {
        return (
                <ViewPager style={styles.viewPager}
                    initialPage={0}
                    scrollEnabled={this.state.scrollEnabled}
                    onPageSelected={this.onPageSelected}
                    orientation="horizontal"
                    transitionStyle="scroll"
                    showPageIndicator={false}
                    animationsAreEnabled={animationsAreEnabled}
                    onPageScroll={(evt) => this.onPageScroll(evt)}
                    onPageScrollStateChanged={(evt) => this.onPageScrollStateChanged(evt)}
                    onMoveShouldSetResponderCapture={(evt) => this.moveShouldSetResponderCapture(evt)}
                    ref={this.viewPager}
                >
                    {pages.map(p => this.renderPage(p))}
                </ViewPager>
        )
    }

I have created PR for it. Thank you @ljsalm089 for providing above example. It helped me a lot.

the branch from @troZee fixed the problem

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nnajiabraham picture nnajiabraham  路  6Comments

ferrannp picture ferrannp  路  10Comments

olhapi picture olhapi  路  4Comments

stefan-girlich picture stefan-girlich  路  9Comments

yashspr picture yashspr  路  5Comments