Flutter:WebView中OnPageStarted/OnPageFinished重复触发问题求助
问题:WebView加载动画反复触发的解决办法
在Flutter项目中使用Cubit状态管理,通过WebView的onPageStarted和onPageFinished控制页面加载动画,但这两个方法在应用生命周期内持续重复触发,导致加载动画反复显示,需实现仅在页面首次加载时触发这两个方法。
解决思路
核心是通过标记首次加载状态,避免后续页面跳转或重加载时重复触发动画:
- 在Cubit中新增状态变量,记录页面是否完成首次加载
- 在
onPageStarted和onPageFinished中添加判断,仅当首次加载时更新加载状态 - 将WebViewController的创建移至StatefulWidget的初始化阶段,避免每次build时重建控制器导致重复绑定回调
步骤1:修改AppCubit,添加首次加载标记
在AppCubit中新增状态变量,控制仅首次加载时更新动画状态:
class AppCubit extends Cubit<AppState> { AppCubit() : super(AppInitialState()); bool isLoading = false; // 新增:标记首次加载是否完成 bool isFirstLoadCompleted = false; void completeLoading({required bool trueFalse}) { // 仅首次加载时更新isLoading状态 if (!isFirstLoadCompleted) { isLoading = trueFalse; emit(AppLoadingState()); } // 加载完成后标记首次加载结束 if (!trueFalse) { isFirstLoadCompleted = true; } } }
步骤2:修改WebViewPage为StatefulWidget并优化控制器创建
原代码在StatelessWidget的build方法中每次重建WebViewController,是重复触发回调的关键原因。改为StatefulWidget后,在initState中仅初始化一次控制器:
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_offline/flutter_offline.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../Module/InternetConnection/internetconnection.dart'; import '../Shared/Component.dart'; import '../Shared/constant.dart'; import '../Shared/cubit/app_cubit.dart'; class WebViewPage extends StatefulWidget { const WebViewPage({Key? key, required this.urlPage, required this.titlePage}) : super(key: key); final String urlPage; final String titlePage; @override State<WebViewPage> createState() => _WebViewPageState(); } class _WebViewPageState extends State<WebViewPage> { // 仅初始化一次WebViewController late final WebViewController _webViewController; @override void initState() { super.initState(); _webViewController = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate( NavigationDelegate( onPageStarted: (String url) { debugPrint('\n onPageStarted : Start Loading\n'); // 仅首次加载时触发加载动画 if (!AppCubit.get(context).isFirstLoadCompleted) { AppCubit.get(context).completeLoading(trueFalse: true); } }, onPageFinished: (String url) { debugPrint('\n onPageFinished : Finish Loading\n'); // 仅首次加载时关闭加载动画 if (!AppCubit.get(context).isFirstLoadCompleted) { AppCubit.get(context).completeLoading(trueFalse: false); } }, ), ) ..loadRequest(Uri.parse(widget.urlPage)); } @override Widget build(BuildContext context) { return BlocProvider( create: (context) => AppCubit(), child: BlocBuilder<AppCubit, AppState>(builder: (context, state) { return OfflineBuilder( connectivityBuilder: (BuildContext context, ConnectivityResult connectivity, Widget child) { final bool connectedWithNetwork = connectivity != ConnectivityResult.none; if (connectedWithNetwork) { return Scaffold( appBar: buildAppBar(context, title: widget.titlePage), body: SizedBox( width: double.infinity, height: double.infinity, child: Stack( children: [ WebViewWidget(controller: _webViewController), AppCubit.get(context).isLoading ? Center( child: Container( width: double.infinity, height: double.infinity, color: Colors.white70.withOpacity(0.1), child: SpinKitFadingCircle( color: blue, size: 100.0, ), ), ) : const SizedBox.shrink(), ], ), ), ); } else { return const NotConnection(); } }, child: const SizedBox.shrink(), ); }), ); } }
关键优化点说明
- 将
WebViewPage改为StatefulWidget,确保WebViewController仅初始化一次,避免每次build时重新绑定回调和加载页面 - 通过Cubit的
isFirstLoadCompleted变量限制动画仅在首次加载时触发 - 用
SizedBox.shrink()替代原代码中的const Stack(),减少不必要的Widget渲染
内容的提问来源于stack exchange,提问作者Asma'a Alndhari
相关产品推荐
相关产品推荐

