In flutter, when using Webview, you sometimes want to display contents above and under it.
Problem - 1 ? Webview need constraints else it couldn't be displayed : you need to wrap the Webview under a container with a fixed size or under a column with an expandable or somethings like that.
Problem - 2 ? Height could be easily fetched but sometimes Webview load asynchronous data like embed script which will change the style of the page. In this situation it's hard to known how and when fetch the Webview height.
With these problem, most of the times your Webview will display a scroll bar and when reached the bottom of the webview user will have trouble to scroll your flutter page. The scroll will conflict with the Webview.
What is the best way to fix that ?
You will need to add an extra around your html and use javascript event handler.
Instead of passing the raw html to the webview we will custom it a little bit.
final htmlFromApi = await getContent();
final html = Uri.dataFromString('''
<html lang="fr">
<meta name="viewport" content="width=device-width user-scalable=no zoom=1.1">
<style>img {max-width: 100%; height: auto}</style>
<body>
<div class="container" id="_flutter_target_do_not_delete">$htmlFromApi</div>
<script>
function outputsize() {
if (typeof window.flutter_inappwebview !== "undefined" && typeof window.flutter_inappwebview.callHandler !== "undefined")
window.flutter_inappwebview.callHandler('newHeight', document.getElementById("_flutter_target_do_not_delete").offsetHeight);
}
new ResizeObserver(outputsize).observe(_flutter_target_do_not_delete)
</script>
</body>
</html>
''', mimeType: "text/html", encoding: Encoding.getByName("utf-8")).toString();
How to use Webview with that :
/// Define it to 1 else the Webview widget will not start loading.
double height = 1;
///some widgets
Container(
height: height,
child: InAppWebView(
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
supportZoom: false,
javaScriptEnabled: true,
disableHorizontalScroll: true,
disableVerticalScroll: true,
),
),
onWebViewCreated: (InAppWebViewController controller) {
controller.addJavaScriptHandler(
handlerName: "newHeight",
callback: (List<dynamic> arguments) async {
int? height = arguments.isNotEmpty ? arguments[0] : await controller.getContentHeight();
if (mounted) setState(() => this.height = height!.toDouble());
});
},
initialUrl: html,
),
),
///some widgets
Explanation :
When the div content will change, an event will be send with the new size. The flutter InAppWebView will listen to it and call the callback. We just can update the WebView's parent container with the current view height. And that's all, the webview is displayed like a widget in flutter without any size issue.