Flutter技术咨询:API列表中CircularProgressIndicator的放置位置
解决Flutter加载PDF时显示CircularProgressIndicator的问题
核心思路
要在点击列表项加载PDF时显示加载指示器,需要通过状态变量控制加载状态,并在UI层根据状态渲染指示器。具体步骤如下:
- 添加布尔类型状态变量标记PDF是否正在加载
- 点击列表项时更新加载状态,加载完成后恢复状态
- 在UI中叠加显示加载指示器(覆盖全屏或列表项区域)
修改后的完整代码
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertest/controller/pdf_api.dart'; import 'package:fluttertest/view/announce_card.dart'; import 'package:fluttertest/view/pdf_viewer.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return GetMaterialApp( home: Scaffold( appBar: AppBar( title: Text('REST API Example'), ), body: Center( child: FetchDataWidget(), ), ), ); } } class FetchDataWidget extends StatefulWidget { @override _FetchDataWidgetState createState() => _FetchDataWidgetState(); } class _FetchDataWidgetState extends State<FetchDataWidget> { Map<String, dynamic> data = {"message": []}; // 添加状态变量:标记PDF是否正在加载 bool _isLoadingPdf = false; @override void initState() { super.initState(); } Future<Map<String, dynamic>> fetchData() async { var headers = { 'API-KEY': '(Confidential)', 'Authorization': '(Confidential)' }; var request = http.Request('GET', Uri.parse('http://vmo.nuboxtech.com/sfa-api/news')); request.headers.addAll(headers); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { var raw = await response.stream.bytesToString(); data = json.decode(raw); print(data); print("Data datatype: ${data.runtimeType}"); } else { print(response.reasonPhrase); } return data; } @override Widget build(BuildContext context) { return Stack( children: [ Container( child: FutureBuilder( future: fetchData(), builder: (BuildContext context, snapshot) { if (snapshot.hasData) { print("Has data: ${snapshot.requireData.toString()}"); return ListView.builder( itemCount: snapshot.requireData["message"].length, itemBuilder: (context, index) { return GestureDetector( onTap: () async { // 点击时设置加载状态为true setState(() { _isLoadingPdf = true; }); try { String pdf = snapshot.requireData["message"][index]['File']; final url = pdf; final file = await PDFApi.loadNetwork(url); openPDF(context, file); } catch (e) { // 处理加载失败的情况 print('PDF加载失败: $e'); Get.snackbar('错误', 'PDF加载失败,请稍后重试'); } finally { // 无论成功失败,恢复加载状态 setState(() { _isLoadingPdf = false; }); } }, child: AnnounceCard( title: snapshot.requireData["message"][index]['Title'], theImage: snapshot.requireData["message"][index]['Image']), ); }, ); } else if (snapshot.hasError) { print("Has error: ${snapshot.error}"); return Center(child: Text('数据加载失败')); } else { print("No data"); return Center(child: CircularProgressIndicator()); } }, ), ), // 加载状态显示全屏指示器 if (_isLoadingPdf) Container( color: Colors.black.withOpacity(0.5), child: Center( child: CircularProgressIndicator(color: Colors.white), ), ) ], ); } void openPDF(BuildContext context, File file) { Get.to(PDFViewerPage( file: file, )); } }
关键修改点说明
- 添加状态变量:在
_FetchDataWidgetState中新增_isLoadingPdf,用于追踪PDF加载状态 - 更新点击逻辑:
- 点击时通过
setState将_isLoadingPdf设为true,触发UI更新显示指示器 - 使用
try-catch-finally确保无论加载成功或失败,最终都会恢复加载状态,隐藏指示器
- 点击时通过
- UI层叠加指示器:用
Stack包裹原内容,当_isLoadingPdf为true时,显示半透明背景的全屏加载指示器,提升用户体验
可选优化方案
- 如果希望每个列表项单独显示加载状态,可将
_isLoadingPdf改为int? _loadingIndex,记录当前加载的列表项索引,在对应item上显示小型指示器 - 使用GetX状态管理替代
setState,适配更复杂的状态场景 - 将加载指示器封装为独立组件,提高代码复用性
内容的提问来源于stack exchange,提问作者arief ariefshamsuddin
相关产品推荐
相关产品推荐

