Flutter:如何在数据上传至后端时添加加载指示器?
解决方案
要实现等待期间的加载动画,只需添加加载状态管理并在UI中对应展示即可,具体修改如下:
修改后的完整代码
import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; import 'package:camera/camera.dart'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:intl/intl.dart'; import 'package:stopfire/home.dart'; import 'camera_screen.dart'; class ConfirmationScreen extends StatefulWidget { final XFile? pictureFile; final Position? position; const ConfirmationScreen({this.pictureFile, this.position, Key? key}) : super(key: key); @override State<ConfirmationScreen> createState() => _ConfirmationScreenState(); } class _ConfirmationScreenState extends State<ConfirmationScreen> { // 新增加载状态变量 bool _isLoading = false; createAlertDialog(BuildContext context){ return showDialog(context: context, builder: (context) { return AlertDialog( title: const Text("¡Tu alerta fue enviada!"), content: ElevatedButton( style: ElevatedButton.styleFrom( primary: Colors.red, textStyle: const TextStyle(color: Colors.white) ), onPressed: (){ Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => const HomePage(), ), ); }, child: const Text("VOLVER"),), ); }); } createErrorAlertDialog(BuildContext context){ return showDialog(context: context, builder: (context) { return AlertDialog( title: const Text("Hubo un error y no recibimos la imagen, vuelve a intentarlo"), content: ElevatedButton( style: ElevatedButton.styleFrom( primary: Colors.red, textStyle: const TextStyle(color: Colors.white) ), onPressed: (){ Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => const HomePage(), ), ); }, child: const Text("VOLVER"),), ); }); } Future<int> uploadImage ()async{ var stream = http.ByteStream(widget.pictureFile!.openRead()); stream.cast(); var length = await widget.pictureFile!.length(); //var uri = Uri.parse('http://10.0.2.2:5000/analyze'); //var uri = Uri.parse("http://172.20.10.4:5000/analyze"); var uri = Uri.parse("http://10.230.61.125:5000/analyze"); var request = http.MultipartRequest('POST', uri); request.files.add( http.MultipartFile( 'file', File(widget.pictureFile!.path).readAsBytes().asStream(), File(widget.pictureFile!.path).lengthSync(), filename: widget.pictureFile!.path.split("/").last ) ); String date = DateFormat("dd/MM/yy HH:mm:ss").format(DateTime.now()); request.fields['taken_at'] = date ; request.fields['latitude'] = widget.position!.latitude.toString(); request.fields['longitude'] = widget.position!.longitude.toString(); request.fields['id_camera'] = "App StopFire" ; request.fields['camera_type'] = "Punto móvil" ; request.fields['zone'] = 'Patrullero' ; var response = await http.Response.fromStream(await request.send()).catchError((onError) => 500); var status = response.statusCode; return status; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Confirmar")), body: Column( children: [ Image.file(File(widget.pictureFile!.path)), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( style: ElevatedButton.styleFrom( primary: Colors.red, textStyle: const TextStyle(color: Colors.white) ), onPressed: _isLoading ? null : (){ Navigator.pop(context); }, child: const Text("VOLVER"),), const Padding( padding: EdgeInsets.fromLTRB(30.0,0,0,0)), ElevatedButton( style: ElevatedButton.styleFrom( primary: Colors.green, textStyle: const TextStyle(color: Colors.white) ), onPressed: _isLoading ? null : () async { setState(() { _isLoading = true; }); // 弹出全屏加载弹窗,禁止用户操作 showDialog( context: context, barrierDismissible: false, builder: (_) => const Center( child: CircularProgressIndicator(color: Colors.white), ), ); try { final status = await uploadImage(); Navigator.pop(context); // 关闭加载弹窗 if (status == 200){ createAlertDialog(context); } else { createErrorAlertDialog(context); } } catch (e) { Navigator.pop(context); createErrorAlertDialog(context); } finally { setState(() { _isLoading = false; }); } }, child: _isLoading ? const CircularProgressIndicator(color: Colors.white) : const Text("ENVIAR")) ], ), ], ), ); } }
关键修改说明
- 新增
_isLoading变量追踪上传状态,加载期间禁用所有按钮防止重复操作 - 点击「ENVIAR」后弹出全屏加载弹窗,明确提示用户当前处于等待状态
- 上传完成或出现异常时,先关闭加载弹窗,再显示结果弹窗
- 按钮自身也会切换为小型加载动画,双重强化加载提示
内容的提问来源于stack exchange,提问作者Juan Cruz Alric Cortabarria
相关产品推荐
相关产品推荐

