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

Flutter:主内容加载后如何带淡出动画彻底移除Stack顶部加载屏

解决方案

要实现加载完成后平滑淡出并彻底移除LoadingBody,同时避免Google Map组件卡顿,核心思路是将加载组件的状态管理与Map组件解耦,只更新必要部分,具体实现如下:

1. 用ValueListenable解耦状态更新

首先将loadingStatus改为ValueNotifier类型,通过ValueListenableBuilder监听状态变化,仅触发加载组件的更新,不会导致整个父组件(包括Map)重建:

// 父组件中定义状态
final ValueNotifier<LoadingStatus> _loadingStatus = ValueNotifier(LoadingStatus.loading);

// 当地图和数据就绪时,更新状态
void _onPageReady() {
  _loadingStatus.value = LoadingStatus.done;
}

2. 封装独立的加载动画组件

创建独立的StatefulWidget负责加载动画的显示、淡出和最终移除,内部管理动画结束后的状态:

class LoadingOverlay extends StatefulWidget {
  final bool isLoading;
  final Color backgroundColor;

  const LoadingOverlay({
    super.key,
    required this.isLoading,
    required this.backgroundColor,
  });

  @override
  State<LoadingOverlay> createState() => _LoadingOverlayState();
}

class _LoadingOverlayState extends State<LoadingOverlay> {
  bool _shouldRender = true;

  @override
  void didUpdateWidget(covariant LoadingOverlay oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 从加载状态切换为完成状态时,延迟执行移除操作(等待动画结束)
    if (oldWidget.isLoading && !widget.isLoading) {
      Future.delayed(const Duration(milliseconds: 500), () {
        if (mounted) {
          setState(() => _shouldRender = false);
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // 彻底移除组件,不再占用资源
    if (!_shouldRender) return const SizedBox.shrink();

    return IgnorePointer(
      // 加载完成后忽略点击事件
      ignoring: !widget.isLoading,
      child: AnimatedOpacity(
        duration: const Duration(milliseconds: 500),
        opacity: widget.isLoading ? 1 : 0,
        child: Container(
          color: widget.backgroundColor,
          child: Center(
            child: Lottie.asset(
              "assets/loading.json",
              // 加载完成后停止动画循环,节省资源
              repeat: widget.isLoading,
            ),
          ),
        ),
      ),
    );
  }
}

3. 在Stack中整合组件

用ValueListenableBuilder包裹加载组件,确保只有加载部分随状态变化更新:

return Stack(
  children: [
    // Google Map组件,不会因加载状态变化而重建
    MapBody(),
    ValueListenableBuilder<LoadingStatus>(
      valueListenable: _loadingStatus,
      builder: (context, status, _) {
        return LoadingOverlay(
          isLoading: status == LoadingStatus.loading,
          backgroundColor: chargeDarkGrey,
        );
      },
    ),
  ],
);

关键优化点

  • 解耦状态更新:用ValueNotifier和ValueListenableBuilder避免父组件整体重建,防止Map卡顿。
  • 彻底移除组件:动画结束后将加载组件替换为SizedBox.shrink(),完全释放其占用的资源。
  • 停止动画循环:加载完成后关闭Lottie的重复播放,进一步降低资源消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:52:34