React-native: RefreshControl for WebView

Created on 1 Jun 2016  路  11Comments  路  Source: facebook/react-native

Hi, I know it's been a while since we deprecate PullToRefreshViewAndroid and move to refreshControl={}, but RefreshControl does not support WebView at all. Therefore, I have no choice but to use PullToRefreshViewAndroid for my WebView.

I have been tapping on the yellow boxes and dismissing them since we deprecate PullToRefreshViewAndroid and now we decided to remove it for good but I hope somehow we can bring back PullToRefreshViewAndroid

Thank you for reading.

Locked

Most helpful comment

I've found a solution to perfectly add pull refresh to webview for both android and ios.
the key is to use the js bridge to notify rn whether enable pull to refresh or not.
the following code was tested against react native 0.38.1.
class YourComponent extends React.Component{
......
state={enablePTR:true}
render(){
return (} onLayout={(ev)=>this.setState({scrollViewHeight:ev.nativeEvent.layout.height})}>
injectedJavaScript="window.onscroll=function(){window.postMessage(document.documentElement.scrollTop||document.body.scrollTop)}"
onMessage={this.onMessage.bind(this)}
/>
)
}

onMessage(e){
//document.documentElement.scrollTop||document.body.scrollTop returns the distance between scroll bar and top position
this.setState({enablePTR:e.nativeEvent.data==0})
}
}

All 11 comments

@facebook-github-bot feature

It would be pretty simple to support RefreshControl on WebView. As for the warnings you can use console.ignoredYellowBox = ['Warning: ...']; in the meantime :)

Thank you for the console.ignoredYellowBox tip!
It'd be great if we can support RefreshControl for WebView
In fact, I would love RefreshControl able to be easily plugged into a "scrollable" view on Android in React like how you use PullToRefreshViewAndroid since I'm using my own WebView component due to some logic requirement (Javascript Interface, etc...)

Any updates on this?

I don't really have the time to work on this at the moment if someone wants to send a PR it would be great. What I suggest is adding support for WebView by doing something as we do in ScrollVIew https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/ScrollView.js#L531

Also have you tried just wrapping your WebView with RefreshControl like you do with PullToRefreshViewAndroid? I think it might actually work.

Also have you tried just wrapping your WebView with RefreshControl like you do with PullToRefreshViewAndroid? I think it might actually work.

This works on android but throws an error on iOS:

I've managed to get this working on iOS and Android with something like:

<ScrollView refreshControl={<RefreshControl .../>}>
  <WebView bounce={false} ... />
</ScrollView>

This approach, however, has the caveat that the scroll event sometimes is captured by the WebView, sometimes by the ScrollView.

iOS:

  • If you swipe down (scroll up), the ScrollView sees the scroll event and the RefreshControl spinner shows.
  • If you first swipe up (scroll down), then change direction and swipe down without lifting your finger, the WebView sees the scroll event, and the RefreshControl spinner never shows.

Android:

  • If you swipe down (scroll up), the spinner shows no matter what. You can't scroll up in the WebView at all.

I think the most robust way forward here is to implement support for RefreshControl directly into WebView, as suggested above.

Thanks for bringing this up. Since this is a feature request rather than a bug report and it has had some discussion I am going to close the issue. I think at this point the best way to go for this sort of extension is to build a separate UI component that has this functionality you want. Good luck!

I've found a solution to perfectly add pull refresh to webview for both android and ios.
the key is to use the js bridge to notify rn whether enable pull to refresh or not.
the following code was tested against react native 0.38.1.
class YourComponent extends React.Component{
......
state={enablePTR:true}
render(){
return (} onLayout={(ev)=>this.setState({scrollViewHeight:ev.nativeEvent.layout.height})}>
injectedJavaScript="window.onscroll=function(){window.postMessage(document.documentElement.scrollTop||document.body.scrollTop)}"
onMessage={this.onMessage.bind(this)}
/>
)
}

onMessage(e){
//document.documentElement.scrollTop||document.body.scrollTop returns the distance between scroll bar and top position
this.setState({enablePTR:e.nativeEvent.data==0})
}
}

@Kerence

state = {
  enablePTR: true
}

render() {
  return (
    <ScrollView refreshControl={} onLayout={(ev) => this.setState({scrollViewHeight: ev.nativeEvent.layout.height})}>
    <WebView
        style={{width:Dimensions.get('window').width,height:this.state.scrollViewHeight}} 
        enableNavigate={false}
        source={{
           uri: this.state.uri
        }}
        ref={(r) => this.webview = r}
        {...this.props}
        injectedJavaScript="window.onscroll = function() { window.postMessage(document.documentElement.scrollTop||document.body.scrollTop)}" 
        onMessage={this.onMessage.bind(this)}/>
  )
}

onMessage(e) {
      //document.documentElement.scrollTop||document.body.scrollTop returns the distance between scroll bar and top position
      this.setState({
        enablePTR: e.nativeEvent.data == 0
      })
}

Maybe it's just me, but I do not see how this should enable the PTR feature:

   enablePTR: e.nativeEvent.data == 0

I also do not find the enableNavigate property in the https://facebook.github.io/react-native/docs/webview.html documentation.

Wouldn't this just tell the ScrollView that it should refresh when the user scrolls to the top again, but not really "on Pull to Refresh"? Or am I missing something? Would be awesome if you could help me out here. Thank you :)

@natterstefan

<ScrollView
  refreshControl={
    <RefreshControl
      enabled={this.state.enablePTR}
      ...
    />
  }
>
Was this page helpful?
0 / 5 - 0 ratings