Flutter и InAppWebView Как получить высоту?
Во флаттере при использовании Webview иногда требуется отображать содержимое над и под ним.
Проблема - 1? Webview нужны ограничения, иначе он не может быть отображен: вам нужно обернуть Webview в контейнер с фиксированным размером или под столбец с расширяемым или что-то в этом роде.
Проблема - 2? Высота может быть легко получена, но иногда Webview загружает асинхронные данные, такие как встроенный скрипт, который изменяет стиль страницы. В этой ситуации трудно понять, как и когда получить высоту веб-просмотра.
С этой проблемой в большинстве случаев ваше веб-представление будет отображать полосу прокрутки, и при достижении нижней части веб-просмотра у пользователя будут проблемы с прокруткой вашей страницы флаттера. Прокрутка будет конфликтовать с веб-просмотром.
Как лучше всего это исправить?
3 ответа
Вам нужно будет добавить дополнительный элемент в свой html и использовать обработчик событий javascript.
Вместо того, чтобы передавать необработанный HTML-код в веб-просмотр, мы немного его настроим.
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() {
window.flutter_inappwebview.callHandler('newHeight');
}
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 {
final int height = await controller.getContentHeight();
setState(() => this.height = height.toDouble());
});
},
initialUrl: html,
),
),
///some widgets
Объяснение :
Когда содержимое div изменится, будет отправлено событие. Флаттер InAppWebView будет его слушать и вызывать обратный вызов. Мы просто можем обновить родительский контейнер 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 ДЕКАБРЬ!!
///
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
}
Основываясь на этом, я создал виджет, который вы можете поместить в список или любую прокручиваемую область. Он может автоматически определять высоту и устанавливать себя.
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
если ты хочешь.