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

Flutter 首次启动弹窗重复弹出、输入时叠加弹窗问题

问题原因

两个异常分别来自3处代码错误:

  • 持久化存值逻辑写错:prefs.setBool(newLaunch, false) 方法第一个参数要求传入字符串类型的存储键名,你传入了布尔类型的newLaunch变量,导致非首次启动的状态从来没有被正确写入本地存储,每次启动读取到的都是默认值true,自然每次都判定为首次启动。
  • 弹窗触发逻辑位置错误:你把调用弹窗的Future.delayed代码写在了build方法里,Flutter每次触发UI重建(比如输入框调用setState、页面刷新、键盘弹出)都会重新执行build方法,等于每次重建都会触发一次弹窗检查。
  • 输入框输入时触发的setState会强制页面重绘,结合上面build里的弹窗逻辑,每输入一个字符就重跑一次build、弹一次窗,最终出现弹窗层层堆叠的问题。
修复方案
  • 把首次启动检查、弹窗触发的逻辑从build方法移到initState生命周期里,保证整个页面生命周期里只执行一次检查,不会因为UI重建重复触发。
  • 修正shared_preferences的存值参数,严格按照setBool(键名, 存储值)的格式传参,确保非首次启动的状态能正确写入本地。
  • 补充必要的安全判断:弹窗弹出前校验组件是否仍挂载、设置弹窗不可通过点击外部蒙层关闭,避免状态未写入就被关闭、组件销毁后调用上下文引发报错。
  • 补全缺失的变量定义、控制器释放逻辑,避免其他隐藏报错。
修复后完整代码
class HomeMenu extends StatefulWidget {
  const HomeMenu({Key? key}) : super(key: key);

  @override
  State<HomeMenu> createState() => _HomeMenuState();
}

class _HomeMenuState extends State<HomeMenu> with TickerProviderStateMixin {
  late TabController _controller;
  TextEditingController textController = TextEditingController();
  String name = '';
  bool newLaunch = true;

  Future<void> showDialogIfFirstLoaded(BuildContext thisContext) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    newLaunch = prefs.getBool('newLaunch') ?? true;
    if (newLaunch) {
      if (!mounted) return;
      showDialog(
        context: thisContext,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            content: TextField(
              controller: textController,
              onChanged: (value) {
                setState(() => name = textController.text);
              },
            ),
            actions: <Widget>[
              TextButton(
                child: const Text('OK'),
                onPressed: () async {
                  await prefs.setBool('newLaunch', false);
                  newLaunch = false;
                  if (mounted) Navigator.pop(thisContext);
                },
              ),
            ],
          );
        },
      );
    }
  }

  @override
  void initState() {
    super.initState();
    _controller = TabController(length: 3, vsync: this);
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      showDialogIfFirstLoaded(context);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        bottom: TabBar(
          controller: _controller,
          tabs: const [
            Tab(text: 'Tab1'),
            Tab(text: 'Tab2'),
            Tab(text: 'Tab3'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _controller,
        children: const [
          Center(child: Text('Page1')),
          Center(child: Text('Page2')),
          Center(child: Text('Page3')),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    textController.dispose();
    super.dispose();
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:33:10