Flutter 插件:WebView与H5页面混合开发flutter_webview_plugin
岁月是什么?无关春秋,只在心态,人生怎么活?恰似三十未满。化解内心的消极,成全生活的信念,充实幸福的内涵,不以物喜,不以己悲,这是一种生存的气魄,也是生命良好的觉悟,更是每个人在人生路上,都应该表现出来的一种生命品质。
废话不多说,先来康康今天的效果图~
效果图(1.1)
:
老思路,先来分析一下:
- 在界面上有5个按钮,点击每个按钮跳转到对应的布局
- 点击H5页面的返回按键,返回到Flutter页面
flutter_webview_plugin引用
在pubspec.yaml下添加依赖,然后Pubget即可
dependencies:
flutter_webview_plugin: ^0.3.11
代码图(2.1)
要是用的话添加导包:
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
好了,到了今天的正文环节
WebView基础使用
/// WebView使用flutter_webview_plugin插件
/// https://pub.dev/packages/flutter_webview_plugin
// ignore: must_be_immutable
class LocalNavWebWidget extends StatefulWidget {
String title;
String url;
LocalNavWebWidget(this.url, this.title);
@override
_LocalNavWebWidgetState createState() =>_LocalNavWebWidgetState(title: title, url: url);
}
class _LocalNavWebWidgetState extends State<LocalNavWebWidget> {
String url;
String title;
_LocalNavWebWidgetState({this.url, this.title});
@override
Widget build(BuildContext context) {
return MaterialApp(
///隐藏Debug标志
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
child: WebviewScaffold(
url: url,
appBar: AppBar(
title: Text(title),
),
//当WebView没加载出来前显示
initialChild: Container(
color: Colors.white,
child: Center(
child: Text("正在加载中...."),
),
),
),
)),
);
}
}
跳转到WebView页面
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) {
return LocalNavWebWidget("https://m.ctrip.com/webapp/you/place/2.html?ishideheader=true&secondwakeup=true&dpclickjump=true&allianceid=66672&sid=1693366&from=https%3A%2F%2Fm.ctrip.com%2Fhtml5%2F",
"百度");
}));
这段代码很好理解:
通过Navigator跳转到WebView页面,传递2个参数
- 传递参数一:Url
- 传递参数二:title
然后通过 WebviewScaffold() 来跳转到H5页面
来康康效果:
效果图(1.2)
:
可以看到,效果是完成了,也能返回到Flutter页面
但是,这也太丑了吧…
接下来,咋们吧AppBar()取消
代码就少了一行AppBar(),就不看代码了,直接看效果图:
效果图(1.3)
;
问题又来了,H5页面跑到了状态栏的下面,这样对于我这种手指头粗糙的糙汉子来说太不友好了,根本点不到…
接下来通过代码让H5页面往下移动一下:
import 'dart:ui';//window导入
//获取的是状态栏的高度
MediaQueryData.fromWindow(window).padding.top)
然后设置padding即可
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
/**
* MediaQueryData.fromWindow(window).padding.top)获取的是状态栏高度
* 需导入import 'dart:ui';
*/
padding:
EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top),
child: WebviewScaffold(
......
),
)),
);
}
效果图(1.5)
:
看到这里,上一个问题H5页面被状态栏覆盖掉解决了
但是又有了新的问题,点击返回的时候,是返回的H5页面的首页.并没有返回到Flutter页面的首页…
不用着急,您往下看
H5返回Flutter首页
第一步,对页面发生改变监听
StreamSubscription<WebViewStateChanged> _stateChanged;
final flutterWebviewPlugin = new FlutterWebviewPlugin();
//页面导航的状态
_stateChanged = flutterWebviewPlugin.onStateChanged.listen((event) {
print("SZJstartLoadUrl${event.url}");
});
当页面发生改变的时候,会调用onStateChanged.listen()这个方法
返回的是当前的状态,通过event.url可以看到当前的接口
代码图(2.2)
:
当点击返回按钮的时候,页面发生了改变,所以会调用onStateChanged.listen()这个方法,咋们只需要判断如果返回的是H5页面,则直接返回到Flutter页面即可,这里有点点绕,大家不用着急,跟着我继续往下看
StreamSubscription<WebViewStateChanged> _stateChanged;
//页面导航的状态
_stateChanged = flutterWebviewPlugin.onStateChanged.listen((event) {
print("SZJstartLoadUrl${event.url}");
switch (event.type) {
case WebViewState.shouldStart:
break;
case WebViewState.startLoad:
if (_isToFlutter(event.url)) {
Navigator.pop(context);
}
break;
case WebViewState.finishLoad:
break;
case WebViewState.abortLoad:
break;
}
});
通过判断event.type的类型,并在WebViewState.startLoad中监听:
//这个是H5要返回的页面
List<String> _urlList = [
"https://m.ctrip.com/html5/",
];
_isToFlutter(String url) {
//默认不反悔H5页面
bool isContaion = false;
_urlList.forEach((element) {
//判断接口是否相同 相同则返回H5页面
if (url?.startsWith(element)) {
isContaion = true;
}
});
return isContaion;
}
简单点来说就是:
Flutter页面跳转到H5页面A
H5页面A点击返回按钮会返回到H5的首页B
当页面发生变化的时候会响应.onStateChanged.listen((event){}
event.url会弹出当前页面的接口
咋们只需要吧点击返回按钮时
H5页面A返回到H5的首页B记录下来,
并且通过与当前页面的接口判断,如果记录的接口和当前返回的接口是同一个,则直接调用Navigator.pop(context);
返回到Flutter页面即可
补充:
WebView还提供了很多的监听,常用的有
- 返回当前接口监听:
StreamSubscription<String> _urlChanged;
_urlChanged = flutterWebviewPlugin.onUrlChanged.listen((String url) {
print("SZJ_urlChanged$url");
});
- 网络错误等情况返回监听
StreamSubscription<WebViewHttpError> _httpErro;
_httpErro = flutterWebviewPlugin.onHttpError.listen((event) {
print("SZJHttpErro网络错误");
});
这些就不带大家演示了,因为我要下班啦, 哈哈哈
最后一点,朋友们一定要养成习惯,在页面销毁的时候,销毁掉这些用过的东西哦~
@override
void dispose() {
super.dispose();
_urlChanged.cancel();
_stateChanged.cancel();
_httpErro.cancel();
flutterWebviewPlugin.dispose();
}
当然了,上面这部分是比较复杂的方法,还有一种简单的方法:
H5页面监听
child: WillPopScope(
onWillPop: () {
Navigator.of(context).pop();
},
child: WebviewScaffold(
url: url,
///是否缩放
withZoom: true,
//是否缓存
withLocalStorage: true,
//默认状态
hidden: true,
//这三个参数解决的是在android端网页自动放大问题
useWideViewPort: true,
displayZoomControls: true,
withOverviewMode: true,
//当WebView没加载出来前显示
initialChild: Container(
color: Colors.white,
child: Column(
//居中
mainAxisAlignment: MainAxisAlignment.center,
children: [
LoadingUtil.loading(context),
Center(
child: Text("正在加载中...."),
),
],
)),
),
))),
可以用WillPopScope包裹WebviewScaffold
必写两个参数:
- 参数一: child 子Widget
- 参数二:onWillPop()按钮返回监听
直接在onWillPop中通过
Navigator.of(context).pop();
返回即可.
原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~