如何在 WebView Flutter 中显示加载指示器?
How to show Loading Indicator in WebView Flutter?
我想在屏幕上显示网页视图数据之前先显示正在加载。怎么做到的?
这是我的代码:
class WebDetailPage extends StatelessWidget {
final String title;
final String webUrl;
final Completer<WebViewController> _controller =
Completer<WebViewController>();
WebDetailPage({
@required this.title,
@required this.webUrl,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colour.white,
title: Text(title, style: TextStyle(color: Colour.midnightBlue)),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colour.midnightBlue),
onPressed: () => Navigator.of(context).pop()),
),
body: Center(
child: WebView(
initialUrl: webUrl,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
),
)
);
}
}
有人可以帮我解决这个问题吗?因为我已经搜索和研究它仍然可以找到解决方案。
完整示例
class WebViewState extends State<WebViewScreen>{
String title,url;
bool isLoading=true;
final _key = UniqueKey();
WebViewState(String title,String url){
this.title=title;
this.url=url;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text(this.title,style: TextStyle(fontWeight: FontWeight.w700)),centerTitle: true
),
body: Stack(
children: <Widget>[
WebView(
key: _key,
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
),
isLoading ? Center( child: CircularProgressIndicator(),)
: Stack(),
],
),
);
}
}
我只是使用 Stack
小部件,所以在 webview 顶部设置加载指示器。当调用 onPageFinished
的 webview 我设置 isLoading=false
变量值并设置透明容器。
您能否Future Builder 轻松解决这个问题。是的,你没听错。
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatelessWidget {
static Future<String> get _url async {
await Future.delayed(Duration(seconds: 1));
return 'https://flutter.dev/';
}
@override
Widget build(BuildContext context) => Scaffold(
body: Center(
child:FutureBuilder(
future: _url,
builder: (BuildContext context, AsyncSnapshot snapshot) => snapshot.hasData
? WebViewWidget(url: snapshot.data,)
: CircularProgressIndicator()),
),);
}
class WebViewWidget extends StatefulWidget {
final String url;
WebViewWidget({this.url});
@override
_WebViewWidget createState() => _WebViewWidget();
}
class _WebViewWidget extends State<WebViewWidget> {
WebView _webView;
@override
void initState() {
super.initState();
_webView = WebView(
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
);
}
@override
void dispose() {
super.dispose();
_webView = null;
}
@override
Widget build(BuildContext context) => _webView;
}
完成示例
完成加载[=]后访问WebView 18=]
class WebViewState extends State<WebViewScreen>{
String title,url;
bool isLoading=true;
final _key = UniqueKey();
WebViewState(String title,String url){
this.title=title;
this.url=url;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text(this.title,style: TextStyle(fontWeight: FontWeight.w700)),centerTitle: true
),
body: Stack(
children: <Widget>[
WebView(
key: _key,
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
),
isLoading ? Center( child: CircularProgressIndicator(),)
: Stack(),
],
),
);
}
}
我们可以使用 IndexedStack 小部件帮助根据索引切换小部件。我们还利用了 webview 的 onPageStarted 和 onPageFinished 属性。使用状态管理,我们在页面开始加载和页面加载完成时更改索引的值。
num pos = 1;
在构建方法中
return Scaffold(
body: IndexedStack(index: pos, children: <Widget>[
WebView(
initialUrl: 'http://pub.dev/',
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (value) {
setState(() {
pos = 1;
});
},
onPageFinished: (value) {
setState(() {
pos = 0;
});
},
),
Container(
child: Center(child: CircularProgressIndicator()),
),
]));
您可以使用 BLOC、Stream 和无状态 Widget
import 'dart:async';
import 'package:rxdart/subjects.dart';
class LoadingWebPageBloc {
//Controllers
final BehaviorSubject<bool> _loadingWebPageController = BehaviorSubject<bool>.seeded(true);
//Sinks
Function(bool) get changeLoadingWebPage => _loadingWebPageController.sink.add;
//Streams
Stream<bool> get loadingWebPageStream => _loadingWebPageController.stream.asBroadcastStream();
@override
void dispose() {
_loadingWebPageController.close();
super.dispose();
}
}
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class CustomWebPagePreview extends StatelessWidget {
final String url;
CustomWebPagePreview({@required this.url});
final LoadingWebPageBloc loadingWebPageBloc = LoadingWebPageBloc();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBar,
body: Container(
child: Stack(
children: <Widget>[
WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (value) {
loadingWebPageBloc.changeloading(true);
},
onPageFinished: (value) {
loadingWebPageBloc.changeloading(false);
},
),
StreamBuilder<bool>(
stream: loadingWebPageBloc.loading,
initialData: true,
builder: (context, snap) {
if (snap.hasData && snap.data == true) {
return Center(
child: CircularProgressIndicator(),
);
}
return SizedBox();
},
),
],
),
),
),
);
}
}
只需使用 Stack 和 Visibility Widget
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MyWebView extends StatefulWidget {
final String url;
const MyWebView({Key? key, this.url = ''}) : super(key: key);
@override
State<MyWebView> createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
bool isLoading = true;
@override
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
if (Platform.isIOS) WebView.platform = CupertinoWebView();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Stack(
children: [
WebView(
initialUrl: widget.url,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
javascriptMode: JavascriptMode.unrestricted,
),
Visibility(
visible: isLoading,
child: const Center(
child: CircularProgressIndicator(),
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(),
),
),
);
}
}
我想在屏幕上显示网页视图数据之前先显示正在加载。怎么做到的?
这是我的代码:
class WebDetailPage extends StatelessWidget {
final String title;
final String webUrl;
final Completer<WebViewController> _controller =
Completer<WebViewController>();
WebDetailPage({
@required this.title,
@required this.webUrl,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colour.white,
title: Text(title, style: TextStyle(color: Colour.midnightBlue)),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colour.midnightBlue),
onPressed: () => Navigator.of(context).pop()),
),
body: Center(
child: WebView(
initialUrl: webUrl,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
),
)
);
}
}
有人可以帮我解决这个问题吗?因为我已经搜索和研究它仍然可以找到解决方案。
完整示例
class WebViewState extends State<WebViewScreen>{
String title,url;
bool isLoading=true;
final _key = UniqueKey();
WebViewState(String title,String url){
this.title=title;
this.url=url;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text(this.title,style: TextStyle(fontWeight: FontWeight.w700)),centerTitle: true
),
body: Stack(
children: <Widget>[
WebView(
key: _key,
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
),
isLoading ? Center( child: CircularProgressIndicator(),)
: Stack(),
],
),
);
}
}
我只是使用 Stack
小部件,所以在 webview 顶部设置加载指示器。当调用 onPageFinished
的 webview 我设置 isLoading=false
变量值并设置透明容器。
您能否Future Builder 轻松解决这个问题。是的,你没听错。
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatelessWidget {
static Future<String> get _url async {
await Future.delayed(Duration(seconds: 1));
return 'https://flutter.dev/';
}
@override
Widget build(BuildContext context) => Scaffold(
body: Center(
child:FutureBuilder(
future: _url,
builder: (BuildContext context, AsyncSnapshot snapshot) => snapshot.hasData
? WebViewWidget(url: snapshot.data,)
: CircularProgressIndicator()),
),);
}
class WebViewWidget extends StatefulWidget {
final String url;
WebViewWidget({this.url});
@override
_WebViewWidget createState() => _WebViewWidget();
}
class _WebViewWidget extends State<WebViewWidget> {
WebView _webView;
@override
void initState() {
super.initState();
_webView = WebView(
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
);
}
@override
void dispose() {
super.dispose();
_webView = null;
}
@override
Widget build(BuildContext context) => _webView;
}
完成示例
完成加载[=]后访问WebView 18=]
class WebViewState extends State<WebViewScreen>{
String title,url;
bool isLoading=true;
final _key = UniqueKey();
WebViewState(String title,String url){
this.title=title;
this.url=url;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text(this.title,style: TextStyle(fontWeight: FontWeight.w700)),centerTitle: true
),
body: Stack(
children: <Widget>[
WebView(
key: _key,
initialUrl: this.url,
javascriptMode: JavascriptMode.unrestricted,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
),
isLoading ? Center( child: CircularProgressIndicator(),)
: Stack(),
],
),
);
}
}
我们可以使用 IndexedStack 小部件帮助根据索引切换小部件。我们还利用了 webview 的 onPageStarted 和 onPageFinished 属性。使用状态管理,我们在页面开始加载和页面加载完成时更改索引的值。
num pos = 1;
在构建方法中
return Scaffold(
body: IndexedStack(index: pos, children: <Widget>[
WebView(
initialUrl: 'http://pub.dev/',
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (value) {
setState(() {
pos = 1;
});
},
onPageFinished: (value) {
setState(() {
pos = 0;
});
},
),
Container(
child: Center(child: CircularProgressIndicator()),
),
]));
您可以使用 BLOC、Stream 和无状态 Widget
import 'dart:async';
import 'package:rxdart/subjects.dart';
class LoadingWebPageBloc {
//Controllers
final BehaviorSubject<bool> _loadingWebPageController = BehaviorSubject<bool>.seeded(true);
//Sinks
Function(bool) get changeLoadingWebPage => _loadingWebPageController.sink.add;
//Streams
Stream<bool> get loadingWebPageStream => _loadingWebPageController.stream.asBroadcastStream();
@override
void dispose() {
_loadingWebPageController.close();
super.dispose();
}
}
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class CustomWebPagePreview extends StatelessWidget {
final String url;
CustomWebPagePreview({@required this.url});
final LoadingWebPageBloc loadingWebPageBloc = LoadingWebPageBloc();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBar,
body: Container(
child: Stack(
children: <Widget>[
WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (value) {
loadingWebPageBloc.changeloading(true);
},
onPageFinished: (value) {
loadingWebPageBloc.changeloading(false);
},
),
StreamBuilder<bool>(
stream: loadingWebPageBloc.loading,
initialData: true,
builder: (context, snap) {
if (snap.hasData && snap.data == true) {
return Center(
child: CircularProgressIndicator(),
);
}
return SizedBox();
},
),
],
),
),
),
);
}
}
只需使用 Stack 和 Visibility Widget
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MyWebView extends StatefulWidget {
final String url;
const MyWebView({Key? key, this.url = ''}) : super(key: key);
@override
State<MyWebView> createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
bool isLoading = true;
@override
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
if (Platform.isIOS) WebView.platform = CupertinoWebView();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Stack(
children: [
WebView(
initialUrl: widget.url,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
javascriptMode: JavascriptMode.unrestricted,
),
Visibility(
visible: isLoading,
child: const Center(
child: CircularProgressIndicator(),
),
)
],
),
bottomNavigationBar: BottomAppBar(
child: Row(),
),
),
);
}
}