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

Flutter中BottomSheet内Socket进度条无法更新的问题

问题解决:Flutter BottomSheet内Socket实时进度不更新的修复

核心问题原因

你在Socket回调中调用的setState是页面State的全局setState,而StatefulBuilder拥有独立的局部setState,页面的状态更新不会触发BottomSheet的UI重建,导致进度条无法实时刷新。


解决方案步骤

1. 改造initSocket,添加进度回调参数

让Socket初始化方法接收一个进度更新回调,直接将实时进度传递给BottomSheet,不再依赖页面的全局进度变量:

void initSocket(String livelapseId, Function(double) onProgressUpdate) {
  socket = IO.io(Endpoints.baseUrl, <String, dynamic>{
    'autoConnect': true,
    'transports': ['websocket'],
  });

  socket!.onConnect((_) {
    print('Connection established');
    socket!.emit('joinRoom', "livelapse:$livelapseId");

    socket!.on('livelapse:progress', (data) {
      print("progress" + data.toString());
      print("operation" + data["operation"].toString());
      double progress = double.parse(data["progress"].toString());
      // 触发外部回调传递进度
      onProgressUpdate(progress);
    });

    socket!.on('livelapse:completed', (data) {
      print("completed" + data.toString());
      // 完成时设置进度为100
      onProgressUpdate(100);
    });

    socket!.on('livelapse:errored', (data) {
      print("errored" + data.toString());
    });
  });

  socket!.onDisconnect((_) => print('Connection Disconnection'));
  socket!.onConnectError((err) => print(err));
  socket!.onError((err) => print(err));
}

2. 修改_showProgressBottomSheet,内部维护进度并绑定回调

在BottomSheet内部用StatefulBuilder的局部setState更新进度,同时将更新方法传递给Socket回调:

void _showProgressBottomSheet(BuildContext context) {
  // BottomSheet内部维护进度变量
  double _sheetProgress = 0;
  // 保存StatefulBuilder的setState方法
  StateSetter? sheetSetState;

  showModalBottomSheet(
    context: context,
    backgroundColor: Colors.transparent,
    builder: (context) => StatefulBuilder(
      builder: (BuildContext context, StateSetter setState) {
        sheetSetState = setState;
        return Container(
          padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 28.h),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.only(
                topLeft: Radius.circular(16.r), topRight: Radius.circular(16.r)),
            color: Colors.white,
          ),
          height: 288.h,
          width: MediaQuery.of(context).size.width,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    'Generating LiveLapse',
                    style: TextStyle(
                        color: Helper.baseBlack,
                        fontSize: 18.sp,
                        fontWeight: FontWeight.w500),
                  ),
                ],
              ),
              SizedBox(height: 20.h),
              Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    isThreeLine: true,
                    leading: Container(
                      padding:
                          EdgeInsets.symmetric(horizontal: 6.w, vertical: 6.h),
                      width: 32.w,
                      height: 32.h,
                      decoration: BoxDecoration(
                          color: Color.fromRGBO(229, 240, 255, 1),
                          borderRadius: BorderRadius.circular(32.r),
                          border: Border.all(
                              color: Color.fromRGBO(245, 249, 255, 1),
                              width: 4.w)),
                      child: SvgPicture.asset(
                        'assets/images/film.svg',
                      ),
                    ),
                    title: Text(
                      "Camera 2 - The Bridges.mp4",
                      style: TextStyle(
                          color: Helper.textColor700,
                          fontSize: 14,
                          fontWeight: FontWeight.w500),
                    ),
                    subtitle: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Text(
                            "Fetching images",
                            style: TextStyle(
                                color: Helper.textColor600,
                                fontSize: 14,
                                fontWeight: FontWeight.w400),
                          ),
                          SizedBox(height: 10.h),
                          Row(mainAxisSize: MainAxisSize.max,
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                           children: [
                            ClipRRect(
                              borderRadius: BorderRadius.circular(4.r),
                              child: LinearPercentIndicator(
                                width: 210.w,
                                fillColor: Helper.textColor300,
                                backgroundColor: Helper.textColor300,
                                progressColor: Helper.primary,
                                padding: EdgeInsets.zero,
                                curve: Curves.easeInOut,
                                barRadius: Radius.circular(4.r),
                                lineHeight: 8.h,
                                // 使用BottomSheet内部的进度变量
                                percent: _sheetProgress / 100
                              ),
                            ),
                            Text(
                              "${(_sheetProgress).toInt()}%",
                              style: TextStyle(
                                  color: Helper.textColor700,
                                  fontSize: 14,
                                  fontWeight: FontWeight.w500),
                            )
                          ])
                        ]),
                    trailing: SvgPicture.asset(
                      'assets/images/checkbox_base.svg',
                    ),
                  ),
                  SizedBox(height: 20.h),
                  Container(
                    height: 52.h,
                    width: double.infinity,
                    child: ElevatedButton(
                      child: Text(
                        "Close",
                        style: TextStyle(
                            color: Colors.white,
                            fontSize: 16,
                            fontWeight: FontWeight.w500),
                      ),
                      style: ButtonStyle(
                          backgroundColor:
                              MaterialStatePropertyAll(Helper.baseBlack),
                          shape: MaterialStateProperty.all(
                            RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(8.r),
                            ),
                          )),
                      onPressed: () {
                        context.pop();
                      },
                    ),
                  ),
                ],
              ),
            ],
          ),
        );
      },
    ),
  );

  // 初始化Socket,传入BottomSheet的进度更新回调
  initSocket(res["_id"], (progress) {
    // 检查BottomSheet是否还存在,避免上下文销毁报错
    if (context.mounted && sheetSetState != null) {
      sheetSetState!(() {
        _sheetProgress = progress;
      });
    }
  });
}

3. 调用方式简化

现在只需直接调用BottomSheet方法即可,无需单独调用initSocket:

_showProgressBottomSheet(context);

关键说明

  • 局部setState的作用:StatefulBuilder提供的setState仅负责重建BottomSheet内部UI,和页面全局状态完全独立,必须用它来触发BottomSheet的进度更新。
  • 回调解耦:通过回调传递进度,避免Socket逻辑和页面/BottomSheet状态强绑定,代码更健壮。
  • 上下文安全检查:context.mounted确保在更新状态时BottomSheet未被关闭,防止出现上下文已销毁的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:24:56