Created
July 31, 2016 23:08
-
-
Save xyos/dcaa43fa561760b9d6194d78e5fb7721 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {WebView, View} from "react-native"; | |
import React, { Component } from 'react' | |
const BODY_TAG_PATTERN = /\<\/ *body\>/; | |
// Do not add any comments to this! It will break line breaks will removed for | |
// some weird reason. | |
var script = ` | |
;(function() { | |
var wrapper = document.createElement("div"); | |
wrapper.id = "height-wrapper"; | |
while (document.body.firstChild) { | |
wrapper.appendChild(document.body.firstChild); | |
} | |
document.body.appendChild(wrapper); | |
var i = 0; | |
function updateHeight() { | |
document.title = wrapper.clientHeight; | |
window.location.hash = ++i; | |
} | |
updateHeight(); | |
window.addEventListener("load", function() { | |
updateHeight(); | |
setTimeout(updateHeight, 1000); | |
}); | |
window.addEventListener("resize", updateHeight); | |
}()); | |
`; | |
const style = ` | |
<style> | |
body, html, #height-wrapper { | |
background-color: #232323; | |
color: #fff; | |
margin: 0; | |
padding: 0; | |
} | |
a, a:visited, a.hover { | |
color: #FFCC55; | |
} | |
#height-wrapper { | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
} | |
</style> | |
<script> | |
${script} | |
</script> | |
`; | |
const codeInject = (html) => html.replace(BODY_TAG_PATTERN, style + "</body>"); | |
/** | |
* Wrapped Webview which automatically sets the height according to the | |
* content. Scrolling is always disabled. Required when the Webview is embedded | |
* into a ScrollView with other components. | |
* | |
* Inspired by this SO answer http://stackoverflow.com/a/33012545 | |
* */ | |
export default class WebViewAutoHeight extends Component{ | |
constructor(props) { | |
super(props) | |
this.state = { | |
realContentHeight: this.props.minHeight, | |
}; | |
this.handleNavigationChange = this.handleNavigationChange.bind(this); | |
} | |
handleNavigationChange(navState) { | |
if (navState.title) { | |
const realContentHeight = parseInt(navState.title, 10) || 0; // turn NaN to 0 | |
this.setState({realContentHeight}); | |
} | |
if (typeof this.props.onNavigationStateChange === "function") { | |
this.props.onNavigationStateChange(navState); | |
} | |
} | |
render() { | |
const {source, style, minHeight, ...otherProps} = this.props; | |
const html = source.html; | |
if (!html) { | |
throw new Error("WebViewAutoHeight supports only source.html"); | |
} | |
if (!BODY_TAG_PATTERN.test(html)) { | |
throw new Error("Cannot find </body> from: " + html); | |
} | |
return ( | |
<View> | |
<WebView | |
{...otherProps} | |
source={{html: codeInject(html)}} | |
scrollEnabled={false} | |
style={[style, {height: Math.max(this.state.realContentHeight, minHeight)}]} | |
javaScriptEnabled | |
onNavigationStateChange={this.handleNavigationChange} | |
/> | |
</View> | |
); | |
} | |
}; | |
WebViewAutoHeight.propTypes={ | |
source: React.PropTypes.object.isRequired, | |
injectedJavaScript: React.PropTypes.string, | |
minHeight: React.PropTypes.number, | |
onNavigationStateChange: React.PropTypes.func, | |
style: WebView.propTypes.style, | |
}; | |
WebViewAutoHeight.defaultProps = { | |
minHeight: 100 | |
} |
This works for me. Can you possibly explain why doing all that manipulation with the js makes a difference?
With the release of Chrome 72 for Android on January 29, 2019, this solution has broken. In handleNavigationChange
, navState.title
is set to the full html of the page instead of the height number expected.
Switching to using messages like demonstrated here: https://stackoverflow.com/a/52556053/904125 seems to be working however. We are still testing with as many devices as possible to make sure it works in all instances, but so far it is working well.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Using react-native 0.34.0, It's causing the page to be blank when
window.location.hash = ++i
is run. Not sure if it's trying to load a URL, but the URL in navState is actuallydata:text/html; charset=utf-8,<html><body>... #4
, and it's shortening this string. Not sure if this is the problem or not.