Flutter使用flutter_pdfview时CircularProgressIndicator显示异常求助
修复方案
问题根因
- 进度条与PDF同时出现:flutter_pdfview依托原生视图渲染,加载过程中原生视图会先渲染空白占位,挡住了上层的Flutter进度指示器,直到PDF内容渲染完成才和进度条同时展示
- 进度条持续加载不消失:部分场景下onRender回调存在兼容问题,加载小体积PDF、本地缓存PDF时不会触发该回调,导致isReady状态永远为false
修复后完整代码
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:flutter_web_browser/flutter_web_browser.dart'; import 'package:path/path.dart'; import 'dart:async'; openBrowserTab() async { await FlutterWebBrowser.openWebPage( url: "https://docs.google.com/forms/d/e/1FAIpQLScdrUJaGxFCLSJV7Njg8WZlqLZOh40Jq000hggexoRjA1-8nQ/viewform?usp=sf_link", customTabsOptions: CustomTabsOptions( toolbarColor: Colors.lightBlueAccent, )); } class PDFViewerPage extends StatefulWidget { final File file; const PDFViewerPage({ Key? key, required this.file, }) : super(key: key); @override _PDFViewerPageState createState() => _PDFViewerPageState(); } class _PDFViewerPageState extends State<PDFViewerPage> { bool isReady = false; final Completer<PDFViewController> _controller = Completer<PDFViewController>(); String errorMessage = ''; @override void initState() { super.initState(); // 3秒兜底超时,避免回调异常导致进度条一直显示 Future.delayed(const Duration(seconds: 3), () { if(mounted && !isReady) { setState(() { isReady = true; }); } }); } @override Widget build(BuildContext context) { final name = basename(widget.file.path); return Scaffold( appBar: AppBar( title: Text(name), actions: <Widget>[ IconButton( icon: Icon( Icons.error, color: Colors.yellow, ), onPressed: () => openBrowserTab(), ) ], ), body: Stack( children: <Widget>[ Offstage( offstage: !isReady, child: PDFView( pageSnap: false, pageFling: false, autoSpacing: false, filePath: widget.file.path, onRender: (_pages) { setState(() { isReady = true; }); }, onPageChanged: (page, total) { // 兜底onRender不触发的场景 if(!isReady) { setState(() { isReady = true; }); } }, onError: (error) { setState(() { errorMessage = error.toString(); }); print(error.toString()); }, onPageError: (page, error) { setState(() { errorMessage = '$page: ${error.toString()}'; }); print('$page: ${error.toString()}'); }, onViewCreated: (PDFViewController pdfViewController) { _controller.complete(pdfViewController); }, ), ), errorMessage.isEmpty ? !isReady ? const Center( child: CircularProgressIndicator(), ) : const SizedBox.shrink() : const Center( child: Text('Please check your internet connection'), ), ], ), ); } }
核心修改点
- 用
Offstage包裹PDFView,加载完成前隐藏原生视图占位,只展示进度指示器,彻底解决两者同时出现的问题 - 新增
onPageChanged兜底回调,兼容onRender不触发的场景 - 新增3秒超时兜底逻辑,就算所有回调都异常,也会自动隐藏进度条
- 替换空Container为更轻量的SizedBox.shrink()优化性能
内容的提问来源于stack exchange,提问作者ZXERSTON
相关产品推荐
相关产品推荐

