개발하자
WebView Flurter에서 로딩 표시기를 표시하는 방법?
Cuire
2023. 1. 29. 04:02
반응형
WebView Flurter에서 로딩 표시기를 표시하는 방법?
화면에 표시되는 웹 보기 데이터 전에 Loading을 먼저 표시하고 싶습니다. 어떻게 그럴 수 있죠?
내 코드는 다음과 같다:
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(),
],
),
);
}
}
나는 웹뷰 세트 로딩 표시기 위에 위젯을 사용할 뿐이다. 웹뷰 호출 시 변수 값을 설정하고 투명 컨테이너를 설정합니다.
할 수 있어요. 네, 맞습니다.
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;
}
전체 예제
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(),
],
),
);
}
}
인덱스 스택 위젯을 사용하면 인덱스에 따라 위젯을 전환할 수 있습니다. 또한 웹 뷰의 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()),
),
]));
BLOCK, 스트림 및 상태 비저장 위젯을 사용할 수 있습니다
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();
},
),
],
),
),
),
);
}
}
스택 및 가시성 위젯만 사용
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(),
),
),
);
}
}
전체 예제
스택 및 가시성 위젯 사용
bool showLoader = true;
Stack(
children: [
Container(
height: _updatedHeight,
child: GestureDetector(
onHorizontalDragUpdate: (updateDetails) {},
child: Container(
margin: EdgeInsets.only(right: 16,left: 16),
width: MediaQuery.of(context).size.width,
child: WebView(
initialUrl: "url",
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_completerController.complete(webViewController);
mainWebController = webViewController;
},
onProgress: (int progress) {
if(progress == 100){
setState(() {
showLoader = false;
});
}
},
onPageStarted: (String url) {
// print("WebView :: onPageStarted :: $url");
},
onPageFinished: (url) async {
double documentElementHeight = double.parse(
await mainWebController.runJavascriptReturningResult("document.documentElement.scrollHeight;"));
// print("WebView :: onPageFinished :: documentElementHeight = $documentElementHeight");
setState(() {
_updatedHeight = documentElementHeight;
});
});
},
navigationDelegate: getNavigationDelegate,
),
),
),
),
Visibility(
visible: showLoader,
child:Padding(
padding: const EdgeInsets.only(top: 50),
child: Container(
width: MediaQuery.of(context).size.width,
child: Center(
child: AWProgressIndicatorWidget(),
),
),
)
)
],
)
Google Codelab
내 생각에 이 해결책은 이다.
자세한 내용은 의 공식 예를 참조하십시오.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({super.key});
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
클린 코드를 원하는 개발자를 위해, 이것을 시도해보세요:
위에
import 'package:flutter/material.dart';
import 'package:ProjectName/src/app.dart'; //replace with your project name
void main() => runApp(MyApp());
위에
import 'package:flutter/material.dart';
import 'package:ProjectName/src/webview_container.dart'; //replace with your project name
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: WebViewClass('https://www.testurl.com', 'test') //replace with your url
)
);
}
}
위에
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewClass extends StatefulWidget {
final url;
final title;
WebViewClass(this.url, this.title);
@override
createState() => WebViewState(this.url, this.title);
}
class WebViewState extends State<WebViewClass>{
var _url;
var _title;
int position = 1 ;
final key = UniqueKey();
WebViewState(this._url, this._title);
doneLoading(String A) {
setState(() {
position = 0;
});
}
startLoading(String A){
setState(() {
position = 1;
});
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: IndexedStack(
index: position,
children: <Widget>[
WebView(
zoomEnabled: false, //I have disabled zoom functionality on the app
initialUrl: _url,
javascriptMode: JavascriptMode.unrestricted,
key: key ,
onPageFinished: doneLoading,
onPageStarted: startLoading,
),
Container(
color: Colors.white,
child: Center(
child: CircularProgressIndicator()),
),
])
),
);
}
}
onPageStarted가 더 좋습니다! URL이 로드되기 시작한 후 로드 표시기가 중지되었기 때문입니다.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarCommon(
title: Text(
widget.title,
),
),
body: Stack(
children: <Widget>[
WebView(
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
onPageStarted: (started){
setState(() {
isLoading = false;
});
},
),
isLoading
? const Center(
child: LoadingIndicator(),
)
: Stack(),
],
),
);
}
만약 누군가 webview_flutter 버전 4.0.2를 사용하여 이것을 우연히 발견한다면, 우리는 's를 사용하고 onPageFinished 콜백을 설정해야 한다.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class PrivacyPolicyPage extends StatefulWidget {
static const routeName = "/privacy_policy";
const PrivacyPolicyPage({super.key});
@override
State<PrivacyPolicyPage> createState() => _PrivacyPolicyPageState();
}
class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {
late final WebViewController _controller;
bool _loading = true;
@override
void initState() {
_controller = WebViewController.fromPlatformCreationParams(
const PlatformWebViewControllerCreationParams())
..setNavigationDelegate(NavigationDelegate(
onPageFinished: (_) => setState(() {
_loading = false;
})))
..setJavaScriptMode(JavaScriptMode.disabled)
..loadFlutterAsset("assets/privacy_policy.html");
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Privacy Policy')),
body: Stack(children: [
WebViewWidget(controller: _controller),
if (_loading) const Center(child: CircularProgressIndicator())
]),
);
}
}
반응형