Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > flutter webview

flutter实现页面多个webview的方案详解

作者:booboom

这篇文章主要为大家详细介绍了flutter如何实现页面多个webview的效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解下

场景

当我们计划使用flutter开发app时,遇到一个页面有多个由富文本编辑器编辑的html内容场景,而且内容很长很大,但是都是一些图文展示的内容。

引入库,版本6.0

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

定义一个Model用来存放webview的相关信息

class WebViewModel {
  String title;
  double height;
  double width;
  HeadlessInAppWebView? headlessWebView;
  int progress;
  String url;
  bool convertFlag;
  WebViewModel({
    required this.title,
    this.width = 0,
    this.height = 0,
    this.headlessWebView,
    this.progress = 0,
    this.url = '',
    this.convertFlag = false,
  });
}

初始化相关属性

final List<WebViewModel> webviewList = [
    WebViewModel(title: '页面一', height: 0, width: 0, url: '', progress: 0, headlessWebView: null),
    WebViewModel(title: '页面二', height: 0, width: 0, url: '', progress: 0, headlessWebView: null),
    WebViewModel(title: '页面三', height: 0, width: 0, url: '', progress: 0, headlessWebView: null),
  ];
// 加载多个webview
for (var item in webviewList) {
  HeadlessInAppWebView? headlessWebView = item.headlessWebView;
  if (headlessWebView != null && !headlessWebView.isRunning()) {
    headlessWebView.run();
  }
}
// ....
initWebview(WebUri("https://cdn.testhtml.com/test/html/20230801/4b6e0db8-0c4f-4a85-a664-997a4e3ed288.html"), 0);
initWebview(WebUri("https://cdn.testhtml.com/test/html/20230802/ddbc1705-ca01-454c-97b6-b20a9c16e30d.html"), 1);
initWebview(WebUri("https://cdn.testhtml.com/test/html/20230802/c60c5bf5-2e14-4a16-b572-d2bb2e7efaaf.html"), 2);

initWebview实现

在实现之前我们也使用常规方案进行加载webview,但是同时加载多个时还是卡顿,无法达到原生的流畅效果,仔细阅读文档后发现inappwebview6.0有一个将无头浏览器模式转换为flutter widget的功能,所以使用无头模式优先加载之后在渲染到页面中,此时发现流畅了很多。

initWebview(WebUri url, int index) {
    webviewList[index].headlessWebView = HeadlessInAppWebView(
      initialUrlRequest: URLRequest(url: url),
      initialSettings: InAppWebViewSettings(
        verticalScrollBarEnabled: false,
      ),
      onProgressChanged: (controller, progress) async {
        // 获取加载进度
        setState(() {
          webviewList[index].progress = progress;
        });
      },
      onLoadStop: (controller, url) async {
        // 当加载结束后进行页面样式的调整
        // 执行一段js,也可以使用字符串的方式,但是作为前端还是js文件更加亲切 = =!!
        // detail_html.js中的内容其实就是控制页面缩放比例之类,也可以直接在生成html时带上,这里只做参考
        await controller.injectJavascriptFileFromAsset(assetFilePath: "assets/js/detail_html.js");
        // 获取网页的宽高并通知flutter
        var bodyWidth = await controller.evaluateJavascript(source: "document.body.offsetWidth");
        var bodyHeight = await controller.evaluateJavascript(source: "document.body.offsetHeight");
        double domWidth = bodyWidth.runtimeType == double ? bodyWidth : (bodyWidth as int).toDouble();
        double domHeight = bodyHeight.runtimeType == double ? bodyHeight : (bodyHeight as int).toDouble();
        webviewList[index].width = domWidth;
        webviewList[index].height = domHeight;
        webviewList[index].convertFlag = true;
        print('=======$bodyWidth=======$bodyHeight======');
        setState(() {});
      },
    );
  }

detail_html.js内容如下:

const head = document.querySelector('head')
const meta = document.createElement('meta')
const body = document.querySelector('body')
meta.setAttribute('name', 'viewport')
meta.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover')
head.appendChild(meta)
const style = document.createElement('style')
style.innerHTML = `
  * {margin: 0; padding: 0;}
  html {width: 100%; overflow-x: hidden;}
  body {display: inline-block; width: 100%; padding: 5px; box-sizing: border-box; }
  img {max-width: 100%; height: auto;}
`
head.appendChild(style)

将加载好的webview转化为widget 此时准备工作已经完成:

convertFlag: 用来控制webview加载状态,加载时显示loading

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          "HeadlessInAppWebView to InAppWebView",
          textScaleFactor: .8,
        ),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: webviewList.map((item) {
            return item.convertFlag
                ? Container(
                    padding: const EdgeInsets.all(12),
                    margin: const EdgeInsets.all(12),
                    height: item.height,
                    child: InAppWebView(
                      headlessWebView: item.headlessWebView, // 关键
                      onWebViewCreated: (controller) async {
                        item.headlessWebView = null;
                      },
                    ),
                  )
                : SizedBox(
                    width: 40,
                    height: 40,
                    child: Center(
                      child: CircularProgressIndicator(
                        value: (item.progress / 100).toDouble(),
                      ),
                    ),
                  );
          }).toList(),
        ),
      ),
    );

还可以进一步优化,判断路由动画结束后再加载,这里就不详细描述了。

由于是测试代码,还有很多优化的地方,这里主要提供了一种多webview加载的优化方案。

到此这篇关于flutter实现页面多个webview的方案详解的文章就介绍到这了,更多相关flutter webview内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文