callstack / react-native-pager-view

React Native wrapper for the Android ViewPager and iOS UIPageViewController.
MIT License
2.77k stars 422 forks source link

Multiple WebViews in PagerView #519

Open velsa opened 2 years ago

velsa commented 2 years ago

I am trying to display multiple webviews (with vertical scroll in them) using PagerView.

The issue that I am having is that when I scroll the web page in WebView, for some reason PagerView also handles the tap-and-drag gesture and sometimes may swipe the page. This is not the desired behavior and I am wondering how can it be avoided?

Here's the working example:

import { Dimensions, View } from 'react-native';
import PagerView from 'react-native-pager-view';
import WebView from 'react-native-webview';

const { width, height } = Dimensions.get('window');

export default function App() {  
  return (
    <View style={{ flex: 1 }}>
      <PagerView overScrollMode='never' style={{ width, height}}>
        <View style={{ flex: 1 }}>
          <WebView source={{ uri: 'https://www.lipsum.com/' }} />
        </View>
        <View style={{ flex: 1 }}>
          <WebView source={{ uri: 'https://cn.lipsum.com/' }} />
        </View>
        <View style={{ flex: 1 }}>
          <WebView source={{ uri: 'https://es.lipsum.com/' }} />
        </View>
        <View style={{ flex: 1 }}>
          <WebView source={{ uri: 'https://it.lipsum.com/' }} />
        </View>
      </PagerView>
    </View>
  );
}

https://user-images.githubusercontent.com/873278/154859909-3cfe0e92-136a-49c6-80ce-8f3ebf03dbe7.mov

Thanks for any help!

tothvoj-gl commented 2 years ago

We are facing the same issue. Here is a nice article explaining the source of the issue: https://bladecoder.medium.com/fixing-recyclerview-nested-scrolling-in-opposite-direction-f587be5c1a04

There is a https://github.com/callstack/react-native-pager-view/issues/164#issuecomment-965032619 which we are using, but it has some drawbacks. We are decreasing the pager swipe sensitivity, however you need to find the sweet spot between fixing this issues and making the swiping too hard.

aleemb commented 2 years ago

@velsa did you manage to work around the issue?

@tothvoj-gl didn't work for me unfortunately.

jiantao88 commented 2 years ago

m

manosKas commented 2 years ago

having the same issue and its a great deal for my company to solve this. if you find any solution to this please share...

zhuanghongji commented 2 years ago

I already found a solution to avoid the problem:

You just need to change WebView to AnAutoHeightWebView and wrap in a ScrollView, it works for my use case and probably works for yours. The fake code like this:

const sceneView = (
  <ScrollView key="1" scrollEnabled={true} showsVerticalScrollIndicator={true}>
    <AnAutoHeightWebView source={ ... } />
  </View>
)

// if react-native-pager-view
<PagerView style={styles.pagerView} initialPage={0}>
  {sceneView1}
  {sceneView2}
</PagerView>

// or if  react-native-tab-view
<TabView style={styles.tabView} 
  renderScene={({ route: { key } }) => {
    switch (key) {
       case '1': 
         return sceneView1
       case '2': 
         return sceneView2
    } 
  }}
/>

Note: you can use AnAutoHeightWebView from react-native-autoheight-webview or something wrote by yourself.

manosKas commented 2 years ago

@zhuanghongji yeah thats more or less what i did but i experimented a bit with pager view 6.0.0-rc2 with lazy load and i got a better result

jiantao88 commented 2 years ago

My solution is to customize a webview container and get touch events in the container `

public boolean dispatchTouchEvent(MotionEvent ev) {
    int x = (int) ev.getX();
    int y = (int) ev.getY();

    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            int deltaX = Math.abs(x - mLastX);
            int deltaY = Math.abs(y - mLastY);
            if (deltaX > deltaY * 1.5) {
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
        default:
            break;

    }
    mLastX = x;
    mLastY = y;

    return super.dispatchTouchEvent(ev);
}

`

manosKas commented 2 years ago

@jiantao88 interesting. does it work flawlessly ? did u put this code in react-native-webview dependency package or in your app's source code ?

jiantao88 commented 2 years ago

@manosKas I didn't use react-native-webview 。This library does not meet my needs,I am using the webview packaged by my own project

Prakunj commented 2 years ago

having the same issue and its a great deal for my company to solve this. if you find any solution to this please share...

hi @manosKas did you find the solution? If yes, please post it here. I have been stuck on these for days now.

manosKas commented 2 years ago

@Prakunj i'm using react-native-pager-view@6.0.0-rc.2, horizontal swipe, with each page being a webview that renders a certain page. Kinda like a gmail app that views your emails. So i wrapped the webviews in scrollview. Then when webview loads, measure the height of the html page, pass height via postMessage to my component and setting the webview height with this value.

As i don't excactly know your specific case, i cant help u any further than that. if you want we can try and communicate more on chat.

TierryBr commented 2 years ago

Any solution for this problem? that use react-native-webview and react-native-pager-view

manosKas commented 1 year ago

just dropping by to see if anyone has solved this...

tarcisioandrade commented 1 year ago

I'm having the same problem, apparently still has no solution :/

zerintia-mariob commented 7 months ago

This works... But what can i do if the webview already had scroll events (like hiding a header)

And styles that set buttons at the end of the page ??

image

I already found a solution to avoid the problem:

  • Up-Down-Left-Right gesture conflict when WebView inside PagerView

You just need to change WebView to AnAutoHeightWebView and wrap in a ScrollView, it works for my use case and probably works for yours. The fake code like this:

const sceneView = (
  <ScrollView key="1" scrollEnabled={true} showsVerticalScrollIndicator={true}>
    <AnAutoHeightWebView source={ ... } />
  </View>
)

// if react-native-pager-view
<PagerView style={styles.pagerView} initialPage={0}>
  {sceneView1}
  {sceneView2}
</PagerView>

// or if  react-native-tab-view
<TabView style={styles.tabView} 
  renderScene={({ route: { key } }) => {
    switch (key) {
       case '1': 
         return sceneView1
       case '2': 
         return sceneView2
    } 
  }}
/>

Note: you can use AnAutoHeightWebView from react-native-autoheight-webview or something wrote by yourself.