flutter开发实战-Webview及dispose关闭背景音

flutter开发实战-Webview及dispose关闭背景音

当在使用webview的时候,dispose需要关闭网页的背景音或者音效。
在这里插入图片描述

一、webview的使用

在工程的pubspec.yaml中引入插件

  webview_flutter: ^4.4.2webview_cookie_manager: ^2.0.6

Webview的使用代码如下

初始化WebViewController

controller = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted)..setBackgroundColor(const Color(0x00000000))..setNavigationDelegate(NavigationDelegate(onProgress: (int progress) {// Update loading bar.},onPageStarted: (String url) {},onPageFinished: (String url) {},onHttpError: (HttpResponseError error) {},onWebResourceError: (WebResourceError error) {},onNavigationRequest: (NavigationRequest request) {if (request.url.startsWith('https://www.youtube.com/')) {return NavigationDecision.prevent;}return NavigationDecision.navigate;},),)..loadRequest(Uri.parse('https://flutter.dev'));

将WebViewController传递给WebViewWidget

@override
Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Simple Example')),body: WebViewWidget(controller: controller),);
}

二、为了方便使用webview,进行封装成一个独立的widget

为了方便使用webview,进行封装成一个独立的widget

WebAppBar

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';/// 自定义Appbar
class WebAppBar extends StatefulWidget implements PreferredSizeWidget {const WebAppBar({Key? key,required this.toolbarHeight,this.elevation,this.backgroundColor,this.leadingWidget,this.trailingWidget,this.centerWidget,this.brightness,this.backgroundImageName}): super(key: key);final double toolbarHeight;final double? elevation;final Color? backgroundColor;final Widget? leadingWidget;final Widget? trailingWidget;final Widget? centerWidget;final Brightness? brightness;final String? backgroundImageName;@override// TODO: implement preferredSizeSize get preferredSize => Size(ScreenUtil().screenWidth, toolbarHeight + ScreenUtil().statusBarHeight);@overrideState<StatefulWidget> createState() => _WebAppBarState();
}class _WebAppBarState extends State<WebAppBar> {@overrideWidget build(BuildContext context) {final SystemUiOverlayStyle overlayStyle =widget.brightness == Brightness.dark? SystemUiOverlayStyle.light: SystemUiOverlayStyle.dark;Widget leadingWidget = (widget.leadingWidget ?? Container());Widget centerWidget = (widget.centerWidget ?? Container());Widget trailingWidget = (widget.trailingWidget ?? Container());return AnnotatedRegion<SystemUiOverlayStyle>(//套AnnotatedRegion是为了增加状态栏控制value: overlayStyle,child: Material(color: Colors.transparent,//套Material是为了增加elevationelevation: widget.elevation ?? 0,child: Container(padding: EdgeInsets.symmetric(horizontal: 0.0),height: widget.toolbarHeight + ScreenUtil().statusBarHeight,decoration: BoxDecoration(color: widget.backgroundColor,),child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Container(height: ScreenUtil().statusBarHeight,),Expanded(child: Container(height: widget.toolbarHeight,alignment: Alignment.center,child: Row(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Container(height: widget.toolbarHeight,child: leadingWidget,),Expanded(child: Container(alignment: Alignment.center,height: widget.toolbarHeight,child: centerWidget,),),Container(height: widget.toolbarHeight,child: trailingWidget,),],),),)],),),),);}
}

使用webview的Widget

import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';// #docregion platform_imports
// Import for Android features.
import 'package:webview_flutter_android/webview_flutter_android.dart';// Import for iOS features.
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
// #enddocregion platform_importsclass WebViewSkeleton extends StatefulWidget {const WebViewSkeleton({Key? key,required this.url,required this.onWebProgress,required this.onWebResourceError,required this.onLoadFinished,this.onWebTitleLoaded,required this.onWebViewCreated,this.appUserAgent,this.webViewUserAgent,}) : super(key: key);final String url;final String? appUserAgent;final String? webViewUserAgent;final Function(int progress) onWebProgress;final Function(WebResourceError error) onWebResourceError;final Function(String? url) onLoadFinished;final Function(String? webTitle)? onWebTitleLoaded;final Function(WebViewController controller) onWebViewCreated;@overrideState<WebViewSkeleton> createState() => _WebViewSkeletonState();
}class _WebViewSkeletonState extends State<WebViewSkeleton> {// WebViewControllerlate final WebViewController _webController;// 尝试3次,每次间隔2秒int _loadTitleTimes = 0;bool _isDisposed = false;@overridevoid initState() {// TODO: implement initStatesuper.initState();_isDisposed = false;initWebController();}void initWebController() {// #docregion platform_featureslate final PlatformWebViewControllerCreationParams params;if (WebViewPlatform.instance is WebKitWebViewPlatform) {params = WebKitWebViewControllerCreationParams(allowsInlineMediaPlayback: true,mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},);} else {params = const PlatformWebViewControllerCreationParams();}final WebViewController controller =WebViewController.fromPlatformCreationParams(params);// #enddocregion platform_featurescontroller..setJavaScriptMode(JavaScriptMode.unrestricted)..setBackgroundColor(const Color(0x00000000))..setUserAgent(widget.webViewUserAgent)..setNavigationDelegate(NavigationDelegate(onProgress: (int progress) {debugPrint('WebView is loading (progress : $progress%)');widget.onWebProgress(progress);},onPageStarted: (String url) {debugPrint('Page started loading: $url');// 网页开始加载webPageLoadedStart();print('onPageStarted url: $url');},onPageFinished: (String url) {debugPrint('Page finished loading: $url');// 网页加载完成print('onPageFinished url: $url');// 加载完成widget.onLoadFinished(url);// 获取网页的标题getWebPageTitle(url: url);},onWebResourceError: (WebResourceError error) {debugPrint('''
Page resource error:code: ${error.errorCode}description: ${error.description}errorType: ${error.errorType}isForMainFrame: ${error.isForMainFrame}''');print("onWebResourceError:${error}");widget.onWebResourceError(error);},onNavigationRequest: (NavigationRequest request) {String url = Uri.decodeComponent(request.url);bool canNavigate = false;if (url.startsWith("http")) {canNavigate = true;}// 允许路由替换return canNavigate? NavigationDecision.navigate: NavigationDecision.prevent;},onUrlChange: (UrlChange change) {debugPrint('url change to ${change.url}');},// onHttpAuthRequest: (HttpAuthRequest request) {//   openDialog(request);// },),);// #docregion platform_featuresif (controller.platform is AndroidWebViewController) {AndroidWebViewController.enableDebugging(true);(controller.platform as AndroidWebViewController).setMediaPlaybackRequiresUserGesture(false);}// #enddocregion platform_features_webController = controller;onWebViewCreated();}void onWebViewCreated() {print("onWebViewCreated");// controller.loadUrl(url);此时也可以初始化一个url_webController.canGoBack().then((res) {// 是否能返回上一级print("controller.canGoBack res: $res");});_webController.currentUrl().then((url) {// 返回当前urlprint("controller.currentUrl url: $url");});_webController.canGoForward().then((res) {//是否能前进print("controller.canGoForward res: $res");});String filePre = "file://";if (widget.url.startsWith(filePre)) {String html = widget.url.substring(filePre.length);DefaultAssetBundle.of(context).loadString('assets/htmls/${html}').then((value) => _webController?.loadHtmlString(value));} else {if (widget.url.startsWith("http://") ||widget.url.startsWith("https://")) {_webController.loadRequest(Uri.parse(widget.url), headers: {'Referer': widget.url,});}}widget.onWebViewCreated(_webController);}@overridevoid dispose() {// TODO: implement disposeprint("_WebViewSkeletonState dispose");_isDisposed = true;webControllerDispose();super.dispose();}Future<void> webControllerDispose() async {/// dispose打开空白页面,关闭音频String url = "about:blank";await _webController?.loadRequest(Uri.parse(url), headers: {});_webController?.clearCache();_webController?.clearLocalStorage();}void webPageLoadedStart() {_loadTitleTimes = 0;}Future<void> getWebPageTitle({required String url}) async {if (_isDisposed) {return;}String? title = await _webController?.getTitle();print("getWebPageTitle:${title}");if (title != null && title.isNotEmpty) {print("webTitle a:${title}");setWebPageTitle(title);} else {try {var result = await _webController?.runJavaScriptReturningResult('window.document.title');print("webTitle document.url:${result}");if (result != null && (result is String) && result.isNotEmpty) {setWebPageTitle(result);} else {result = await _webController?.runJavaScriptReturningResult('window.document.getElementsByTagName("title")[0]');print("webTitle document.getElementsByTagName:${result}");setWebPageTitle(result);}} catch (e) {print("getWebPageTitle:${e.toString()}");// 最多尝试三次if (_loadTitleTimes < 3) {Future.delayed(Duration(seconds: 2), () {_loadTitleTimes++;getWebPageTitle(url: url);});}}}}// 设置页面标题void setWebPageTitle(data) {if (widget.onWebTitleLoaded != null) {widget.onWebTitleLoaded!(data);}}// 返回void goBack() {_webController?.canGoBack().then((res) {// 是否能返回上一级print("controller.canGoBack res: $res");if (true == res) {_webController?.goBack();}});}// 刷新void reload() {_webController?.reload();}@overrideWidget build(BuildContext context) {return buildWebView(context);}Widget buildWebView(BuildContext context) {return WebViewWidget(controller: _webController,);}
}

使用web view的页面webviewPage

class WebViewPage extends StatefulWidget {const WebViewPage({Key? key,this.arguments,}) : super(key: key);final Object? arguments;@overrideState<WebViewPage> createState() => _WebViewPageState();
}class _WebViewPageState extends State<WebViewPage> {String title = "";String? url;// WebViewControllerWebViewController? _webViewController;double webProgress = 0.0;String? webViewUserAgent;String? appUserAgent;String? webTitle;@overridevoid initState() {// TODO: implement initStateif (widget.arguments != null && widget.arguments is Map) {Map obj = widget.arguments as Map;url = obj["url"];webViewUserAgent = obj['webViewUserAgent'];appUserAgent = obj['appUserAgent'];webTitle = obj['webTitle'];}loggerInfo("_WebViewPageState arguments:${widget.arguments}");loggerInfo("_WebViewPageState url:${url}");super.initState();}@overridevoid dispose() {// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: WebAppBar(toolbarHeight: 44.0,backgroundColor: Theme.of(context).primaryColor,centerWidget: Text(webTitle ?? title,textAlign: TextAlign.center,overflow: TextOverflow.ellipsis,style: TextStyle(fontSize: 17,color: ColorUtil.hexColor(0xffffff),fontWeight: FontWeight.w600,fontStyle: FontStyle.normal,decoration: TextDecoration.none,),),leadingWidget: Row(mainAxisAlignment: MainAxisAlignment.start,crossAxisAlignment: CrossAxisAlignment.center,children: [IconButton(padding: EdgeInsets.all(0.0),onPressed: () {webViewGoBack(context);},icon: Icon(Icons.arrow_back_ios,color: Colors.white,size: 24.0,),),IconButton(padding: EdgeInsets.all(0.0),onPressed: () {navigatorBack(context);},icon: Icon(Icons.close_rounded,color: Colors.white,size: 30.0,),),],),trailingWidget: Row(mainAxisAlignment: MainAxisAlignment.end,crossAxisAlignment: CrossAxisAlignment.center,children: [SizedBox(width: 28.0,),IconButton(padding: EdgeInsets.all(0.0),onPressed: () {webViewReload();},icon: Icon(Icons.refresh_outlined,color: Colors.white,size: 28.0,),),],),),body: Stack(children: [WebViewSkeleton(url: url ?? "",onWebResourceError: (WebResourceError error) {if (mounted) {// TODO onWebResourceError}},onWebProgress: (int progress) {if (mounted) {// TODO onWebProgressdouble precent = progress / 100.0;if (precent > 1.0) {precent = 1.0;}if (precent < 0.0) {precent = 0.0;}setState(() {webProgress = precent;loggerInfo("webProgress:${webProgress}");});}},onLoadFinished: (String? url) {if (mounted) {// TODO onLoadFinished}},onWebTitleLoaded: (String? webTitle) {if (mounted) {String? aWebTitle;if ('""' != webTitle) {aWebTitle = webTitle;}setState(() {title = aWebTitle ?? "";});}},onWebViewCreated: (WebViewController controller) {_webViewController = controller;},),buildProgressIndicator(context),],),);}Widget buildProgressIndicator(BuildContext context) {return (webProgress != 1.0)? LinearProgressIndicator(backgroundColor: Colors.transparent,valueColor: AlwaysStoppedAnimation(ColorUtil.hexColor(0x3b93ff)),value: webProgress,minHeight: 2,): Container();}void navigatorBack(BuildContext context) {Navigator.of(context).pop();}void webViewGoBack(BuildContext context) {_webViewController?.canGoBack().then((res) {// 是否能返回上一级loggerInfo("controller.canGoBack res: $res");if (true == res) {_webViewController?.goBack();} else {navigatorBack(context);}});}void webViewReload() {_webViewController?.reload();}
}

三、解决dispose关闭背景音乐

解决dispose关闭背景音乐的问题,当widget被dispose的时候,我们可以通过加载一个空白页面,来实现这个关闭背景音乐。
加载空白

代码如下

@overridevoid dispose() {// TODO: implement disposeprint("_WebViewSkeletonState dispose");_isDisposed = true;webControllerDispose();super.dispose();}Future<void> webControllerDispose() async {/// dispose打开空白页面,关闭音频String url = "about:blank";await _webController?.loadRequest(Uri.parse(url), headers: {});_webController?.clearCache();_webController?.clearLocalStorage();}

四、小结

flutter开发实战-Webview及dispose关闭背景音

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/371856.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【知网CNKI-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

Trinity:转录组从头组装

安装 #下载安装包 wget -c https://github.com/trinityrnaseq/trinityrnaseq/releases/download/Trinity-v2.15.1/trinityrnaseq-v2.15.1.FULL.tar.gztar -xzvf trinityrnaseq-v2.15.1.FULL.tar.gz cd trinityrnaseq-v2.15.1 make make plugins #安装依赖 mamba install -c bio…

Vue3使用markdown编辑器之Bytemd

官网地址&#xff1a;https://bytemd.js.org/playground GitHub地址&#xff1a;https://github.com/bytedance/bytemd ByteMD 是字节跳动出品的富文本编辑器&#xff0c;功能强大&#xff0c;可以免费使用&#xff0c;而且支持很多掘金内置的主题&#xff0c;写作体验很棒。 …

Flask之电子邮件

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、使用Flask-Mail发送电子邮件 1.1、配置Flask-Mail 1.2、构建邮件数据 1.3、发送邮件 二、使用事务邮件服务SendGrid 2.1、注册SendGr…

element-ui输入框如何实现回显的多选样式?

废话不多说直接上效果&#x1f9d0; 效果图 <template><div><el-form:model"params"ref"queryForm"size"small":inline"true"label-width"68px"><el-form-item label"标签" prop"tag&q…

安全防御(防火墙)

第二天&#xff1a; 1.恶意程序---一般会具有一下多个或则全部特点 1.非法性&#xff1a;你未经授权它自动运行或者自动下载的&#xff0c;这都属于非法的。那恶意程序一般它会具有这种特点&#xff0c; 2.隐蔽性&#xff1a;一般隐藏的会比较深&#xff0c;目的就是为了防止…

MySQL性能优化 一、系统配置优化

数据库优化纬度有四个&#xff1a; 硬件升级、系统配置、表结构设计、SQL语句及索引。 优化选择&#xff1a; 优化成本&#xff1a;硬件升级 > 系统配置 > 表结构设计 > SQL语句及索引优化效果&#xff1a;硬件升级 < 系统配置 < 标结果设计 < SQL语句及索…

无线领夹麦克风品牌排名,揭秘国产领夹麦克风哪个品牌好

在自媒体行业迅猛发展的浪潮中&#xff0c;领夹麦克风作为音频采集的关键设备&#xff0c;其市场需求正经历着前所未有的激增。面对市场上众多品牌和型号的选择&#xff0c;如何做出既符合个人需求又不失专业水准的决策&#xff0c;成为了消费者亟待解决的问题。 我特意为大家…

springboot+vue+mybatis图书销售管理系统+PPT+论文+讲解+售后

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括图书销售管理系统的网络应用&#xff0c;在外国图书销售管理系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。图书销售管理系统具有网上图书信息管…

Python学习中使用循环(for, while)

在Python编程语言中&#xff0c;循环是一个非常重要的概念&#xff0c;可以帮助我们在代码中重复执行某些操作。Python支持两种主要的循环结构&#xff1a;for 循环和 while 循环。 1. for 循环 for 循环用于遍历一个序列&#xff08;如列表、元组、字符串&#xff09;或其他…

Java反射与Fastjson的危险反序列化

什么是Java反射&#xff1f; 在前文中&#xff0c;我们有一行代码 Computer macBookPro JSON.parseObject(preReceive,Computer.class); 这行代码是什么意思呢&#xff1f;看起来好像就是我们声明了一个名为 macBookPro 的 Computer 类&#xff0c;它由 fastjson 的 parseObje…

浅谈OpenCV的多对象匹配透明图像的实现,以及如何匹配半透明控件

引子 OpenCV提供的templateMatch只负责将&#xff08;相关性等&#xff09;计算出来&#xff0c;并不会直接提供目标的对应坐标&#xff0c;一般来说我们直接遍历最高的相关度&#xff0c;就可以得到匹配度最高的坐标。但是这样一般只能得到一个坐标。在实际操作中&#xff0c;…

Hadoop-12-Hive 基本介绍 下载安装配置 MariaDB安装 3台云服务Hadoop集群 架构图 对比SQL HQL

章节内容 上一节我们完成了&#xff1a; Reduce JOIN 的介绍Reduce JOIN 的具体实现DriverMapperReducer运行测试 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&am…

Atom CMS v2.0 SQL 注入漏洞(CVE-2022-25488)

前言 CVE-2022-25488 是一个发现于 Telesquare SDT-CW3B1 设备中的命令注入漏洞。这一漏洞可以被未经认证的远程攻击者利用&#xff0c;通过特殊构造的 HTTP 请求在设备上执行任意命令。以下是关于该漏洞的详细信息&#xff1a; 漏洞详细信息 漏洞编号: CVE-2022-25488影响范…

记录一次ffmpeg手动编译出现的问题

前言部分 使用环境: ubuntu 22.04 最近手动编译了一次的ffmpeg&#xff08;参考博客ffmpeg学习&#xff1a;ubuntu下编译ffmpeg(全网最懒的编译脚本)&#xff09;&#xff0c;但是过程出现了一些问题&#xff0c;因此在此记录一下&#xff0c;若有疑问&#xff0c;欢迎讨论~。 …

【MotionCap】pycharm 远程在wsl2 ubuntu20.04中root的miniconda3环境

pycharm wsl2 链接到pycharmsbin 都能看到内容,/root 下内容赋予了zhangbin 所有,pycharm还是看不到/root 下内容。sudo 安装了miniconda3 引发了这些问题 由于是在 root 用户安装的miniconda3 所以安装路径在/root/miniconda3 里 这导致了环境也是root用户的,会触发告警 WA…

【MySQL】MySQL锁冲突排障纪要

【MySQL】MySQL锁冲突排障纪要 开篇词&#xff1a;干货篇&#xff1a;1.查看当前innodb status,里面包含事务,锁占用情况2.查看mysql进程状态3.查看innodb事务&#xff0c;锁&#xff0c;锁等待情况4.定位持有锁的线程信息 总结篇&#xff1a;一、锁冲突的原因二、锁冲突的表现…

BigDecimal(double)和BigDecimal(String)有什么区别?BigDecimal如何精确计数?

BigDecimal(double)和BigDecimal(String)的区别 double是不精确的&#xff0c;所以使用一个不精确的数字来创建BigDecimal&#xff0c;得到的数字也是不精确的。如0.1这个数字&#xff0c;double只能表示他的近似值。所以&#xff0c;当我们使用new BigDecimal(0.1)创建一个Bi…

一.2.(4)放大电路静态工作点的稳定;

1.Rb对Q点及Au的影响 输入特性曲线&#xff1a;Rb减少&#xff0c;IBQ&#xff0c;UBEQ增大 输出特性曲线&#xff1a;ICQ增大&#xff0c;UCEQ减少 AUUO/Ui分子减少&#xff0c;分母增大&#xff0c;但由于分子带负号&#xff0c;所以|Au|减少 2.Rc对Q点及Au的影响 输入特性曲…

Google账号输入用户名和密码后提醒要到手机通知点是,还要点击数字,但是我手机收不到

有一些朋友换了一个新的电脑后手机登录谷歌账号时&#xff0c;用户名和密码都正确输入以后&#xff0c;第三步弹出一个提示&#xff0c;要在手机上的通知栏点击是&#xff0c;并且点击手机上相应的数字才能继续登录。 但是自己的手机上下拉通知栏却没有来自谷歌的通知&#xf…