You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter全局Snackbar中实现带下载百分比的进度指示器?

问题根因

  • 你每次触发进度回调时都直接调用showSnackBar,没有先隐藏之前的SnackBar,新的SnackBar会进入队列等待旧的自动消失才会显示,自然看不到进度更新
  • 你用的是当前触发下载的页面的BuildContext,跳转到其他页面后,这个context对应的ScaffoldMessenger已经不在前台,SnackBar会跟着旧页面消失,无法跨页面显示
  • snacBarDownloading是静态传入progress值,构建完成后不会自动响应静态变量的变化

修复步骤

第一步:配置全局ScaffoldMessenger,实现跨页面显示SnackBar

在项目的MaterialApp入口配置全局key,不需要依赖页面context就能调用SnackBar:

// 全局定义顶层ScaffoldMessenger的key
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();

// 注册到MaterialApp
MaterialApp(
  scaffoldMessengerKey: scaffoldMessengerKey,
  // 其余原有配置保持不变
)

第二步:修改CustomSnackBar逻辑

每次更新进度前先移除旧的下载SnackBar,再显示新的,同时适配全局ScaffoldMessenger:

class CustomSnackBar {
  static bool isDownloading = false;
  static String progress = "0%";
  CustomSnackBar._();

  static Future<void> downloadFile(String fileUrl, String fileName) async {
    Dio dio = Dio();
    isDownloading = true;
    progress = "0%";
    try {
      var dir = await getApplicationDocumentsDirectory();
      // 先确保下载目录存在,避免写入失败
      await Directory("${dir.path}/notifications_files").create(recursive: true);
      await dio.download(
        fileUrl, 
        "${dir.path}/notifications_files/$fileName.pdf",
        onReceiveProgress: (rec, total) {
          if(total <= 0) return;
          progress = '${((rec / total) * 100).toStringAsFixed(0)} %';
          updateDownloadSnackBar();
        }
      );
      isDownloading = false;
      // 下载完成后隐藏进度条,显示成功提示
      scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
      scaffoldMessengerKey.currentState?.showSnackBar(
        const SnackBar(content: Text("下载完成"), duration: Duration(seconds: 2))
      );
    } catch (e) {
      isDownloading = false;
      scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
      scaffoldMessengerKey.currentState?.showSnackBar(
        SnackBar(content: Text("下载失败:${e.toString()}"), duration: const Duration(seconds: 2))
      );
    }
  }

  static updateDownloadSnackBar() {
    // 先移除之前的下载SnackBar,再显示最新进度的SnackBar
    scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
    scaffoldMessengerKey.currentState?.showSnackBar(
      SnackBar(
        duration: const Duration(days: 100),
        backgroundColor: kPrimaryColor,
        content: snacBarDownloading(progress),
        action: SnackBarAction(
          textColor: kWhiteColor,
          label: 'Dismiss',
          onPressed: () {
            scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
          },
        ),
      ),
    );
  }
}

Widget snacBarDownloading(String progress) {
  return Row(children: [
    const SizedBox(
        width: 25,
        height: 25,
        child: CircularProgressIndicator(color: kWhiteColor)),
    const SizedBox(
      width: 10,
    ),
    Text("Downloading $progress ...",
        style: const TextStyle(color: kWhiteColor))
  ]);
}

第三步:修改调用逻辑

不需要再传入当前页面的context:

return InkWell(
  onLongPress: () {
    if (!CustomSnackBar.isDownloading &&
        widget.notificationList[index].fileUrl != null &&
        widget.notificationList[index].fileUrl!.isNotEmpty) {
      CustomSnackBar.downloadFile(
          widget.notificationList[index].fileUrl!,
          widget.notificationList[index].serviceId!);
    }
  },
  // 其余原有配置保持不变
);

内容的提问来源于stack exchange,提问作者Jed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 01:15:04