WebView is used to display the Web Content into our Application. Web Content may be any URL or HTML data. In this blog, I have highlighted how to create a dynamic height Webview. It is the toughest and required task in react native.
The problem of React Native Webview-
React Native does not provide dynamic height to Webview Component, so we need to provide fix height to our WebView but fix height is not suitable for the Html content. If we use Webview with some other View Component then Webview takes all screen size and other views are not displayed.
How can solve it?
I have read & used some library but the issue has not solved in case. So, I have read one library “react-native-webview-autoheight” and create my own Webview Component name MyWebview. For the solution, I have used onMessage props. it is a function that is invoked when the webview calls window.postMessage
. Setting this property will inject a postMessage
global into your webview, but will still call pre-existing values of postMessage
.
window.postMessage
accepts one argument, data
which will be available on the event object, event.nativeEvent.data
. data
must be a string.
For this facility of Webview, I have injected the Javascript to Webview that computes the height of the content and triggered the function postMessage
and pass the height of the content with this function and get this size data on onMessage props function and update the webview height state.
Source code for the injected script
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const injectedScript = function() { function waitForBridge() { if (window.postMessage.length !== 1){ setTimeout(waitForBridge, 200); } else { postMessage( Math.max(document.documentElement.clientHeight, document.documentElement.scrollHeight, document.body.clientHeight, document.body.scrollHeight) ) } } waitForBridge(); }; |
Source code of My Webview-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
export default class MyWebView extends Component { state = { webViewHeight: Number }; static defaultProps = { autoHeight: true, } constructor (props: Object) { super(props); this.state = { webViewHeight: this.props.defaultHeight } this._onMessage = this._onMessage.bind(this); } _onMessage(e) { this.setState({ webViewHeight: parseInt(e.nativeEvent.data) }); } stopLoading() { this.webview.stopLoading(); } reload() { this.webview.reload(); } render () { const _w = this.props.width || Dimensions.get('window').width; const _h = this.props.autoHeight ? this.state.webViewHeight : this.props.defaultHeight; const androidScript = 'window.postMessage = String(Object.hasOwnProperty).replace(\'hasOwnProperty\', \'postMessage\');' + '(' + String(injectedScript) + ')();'; const iosScript = '(' + String(injectedScript) + ')();' + 'window.postMessage = String(Object.hasOwnProperty).replace(\'hasOwnProperty\', \'postMessage\');'; return ( <WebView ref={(ref) => { this.webview = ref; }} injectedJavaScript={Platform.OS === 'ios' ? iosScript : androidScript} scrollEnabled={this.props.scrollEnabled || false} onMessage={this._onMessage} javaScriptEnabled={true} automaticallyAdjustContentInsets={true} {...this.props} style={[{width: _w}, this.props.style, {height: _h}]} /> ) } } |
Source code to invoke MyWebview-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<MyWebView source={{ // line-height:10px text-align: justify; html: "<style>body {max-width: 100%; font-family: sans-serif;overflow-wrap: break-word;word-wrap: break-word; }</style>" + "<body>" + this.state.product.short_description + "</body>" }} automaticallyAdjustContentInsets={true} scalesPageToFit={true} // width={SCREEN_WIDTH - ThemeConstant.MARGIN_NORMAL} startInLoadingState={true} height={20} style={{ elevation: -1, height: 20, }} /> |
References:-
https://facebook.github.io/react-native/docs/webview
https://www.npmjs.com/package/react-native-webview-autoheight