Flutter和InAppWebView如何获得高度?



在flutter中,当使用Webview时,您有时希望在其上方和下方显示内容。

问题- 1 ?Webview需要约束,否则它无法显示:你需要将Webview包装在一个固定大小的容器下,或者包装在一个可扩展的列下,或者类似的东西。

问题- 2 ?高度可以很容易地获取,但有时Webview加载异步数据,如嵌入脚本,这将改变页面的风格。在这种情况下,很难知道如何以及何时获取Webview的高度。

由于这些问题,大多数时候您的Webview将显示滚动条,当到达Webview底部时,用户将难以滚动您的flutter页面。滚动条将与Webview发生冲突。

解决这个问题的最好方法是什么?

您需要在html周围添加额外的内容,并使用javascript事件处理程序。

我们不把原始的html传递给webview,而是稍微自定义一下。

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();

如何使用Webview:

/// 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

解释:

当div内容改变时,将发送一个带有新大小的事件。flutter InAppWebView将监听它并调用回调。我们可以用当前视图的高度更新WebView的父容器。就是这样,webview就像一个小部件一样在抖动,没有任何大小问题。

int? contentHeight = await _controller?.getContentHeight();
double? zoomScale = await _controller?.getZoomScale();
double htmlHeight = contentHeight!.toDouble() * zoomScale!;
double htmlHeightFixed =
double.parse(htmlHeight.toStringAsFixed(2));
if (htmlHeightFixed == 0.0) {
return;
}
setState(() {
_htmlHeight = htmlHeightFixed + 0.1;
});

更新2022年12月!!

///
double webViewHeight = 1;
WebViewController? controller;

WebView(
initialUrl: widget.url,
onWebViewCreated: (WebViewController c) {
controller = c;
},
onPageFinished: (_) {
updateHeight();
},
javascriptMode: JavascriptMode.unrestricted,
);
// This calculates the height
void updateHeight() async {
double height = double.parse(await 
controller!.runJavascriptReturningResult('document.documentElement.scrollHeight;'));
print(height); // prints height
}
在此基础上,我创建了一个小部件,你可以把它放在listview或任何可滚动的区域它可以自动检测高度和设置自己
class DynamicHeightWebView extends StatefulWidget {
///
final String url;
///
const DynamicHeightWebView({Key? key, required this.url}) : super(key: key);
@override
State<DynamicHeightWebView> createState() => _DynamicHeightWebViewState();
}
class _DynamicHeightWebViewState extends State<DynamicHeightWebView>
with AutomaticKeepAliveClientMixin {
///
double webViewHeight = 1;
WebViewController? controller;
@override
Widget build(BuildContext context) {
super.build(context);
return SizedBox(
height: webViewHeight,
child: WebView(
initialUrl: widget.url,
onWebViewCreated: (WebViewController c) {
controller = c;
},
onPageFinished: (_) {
updateHeight();
},
javascriptMode: JavascriptMode.unrestricted,
),
);
}
void updateHeight() async {
double height = double.parse(await controller!.runJavascriptReturningResult(
'document.documentElement.scrollHeight;'));
if (webViewHeight != height) {
setState(() {
webViewHeight = height;
});
}
}
@override
bool get wantKeepAlive => true;
}

如果你愿意,可以删除AutomaticKeepAliveClientMixin

最新更新