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

Flutter中点击rflutter_alert弹窗内TextField时弹窗重复加载的问题

问题分析

你遇到的这个弹窗反复弹出、无法正常唤起键盘的问题,核心原因有两个:

  • 你在verificarUsuario()方法内部创建了TextEditingController,每次调用这个方法都会生成全新的控制器。当点击TextField时,控制器的状态变化会触发页面重建,而initState又会重新调用验证方法,导致弹窗反复出现。
  • 直接在initState里调用异步的用户验证逻辑,没有处理好异步操作与组件状态的关系,容易因为异步回调触发的重建导致重复执行验证逻辑。
修复方案

我整理了几个关键修复步骤,同时附上修改后的完整代码:

1. 把TextEditingController提升为State类成员

将控制器定义在State类的顶部,而不是方法内部,这样可以保持状态的持久化,避免每次重建都生成新的控制器。

2. 添加标志位防止重复验证

新增一个_isVerified布尔变量,用来标记是否已经完成了用户验证,避免initState重复触发弹窗。

3. 优化空安全处理

不要直接用!强制解包currentUser,改用空安全的方式处理,避免潜在的空指针异常。

修改后的完整代码

class MuroScreen extends StatefulWidget { 
  const MuroScreen({Key? key}) : super(key: key); 
  @override 
  _MuroScreenState createState() => _MuroScreenState(); 
} 
class _MuroScreenState extends State<MuroScreen> { 
  CollectionReference userRef = FirebaseFirestore.instance.collection('clientes');
  // 提升为类成员变量,持久化状态
  final nameController = TextEditingController();
  final passwordController = TextEditingController();
  // 添加标志位,防止重复触发验证弹窗
  bool _isVerified = false;

  Future<void> salir() async { 
    await FirebaseAuth.instance.signOut().catchError((error){ 
      print(error.toString()); 
    }); 
    Navigator.of(context).push(MaterialPageRoute(builder: (c)=>const MyHomePage001()),); 
  } 

  Future<void> verificarUsuario() async{
    // 已经验证过就直接返回,避免重复弹窗
    if (_isVerified) return;
    
    final currentUser = FirebaseAuth.instance.currentUser;
    // 空安全处理:如果没有登录用户,直接终止逻辑
    if (currentUser == null) {
      print("当前无登录用户");
      return;
    }
    
    DocumentSnapshot snapshotUser = await userRef 
      .doc(currentUser.phoneNumber) 
      .get(); 
    print("existe?"+snapshotUser.exists.toString()); 
    if(snapshotUser.exists){ 
      // 用户已存在,标记验证完成
      setState(() {
        _isVerified = true;
      });
      print("si EXISTE"); 
    } else { 
      // 用户不存在,显示登录弹窗
      print("no EXISTE"); 
      Alert( 
        context: context, 
        title: "LOGIN", 
        content: Column( 
          children: <Widget>[ 
            TextField( 
              controller: nameController, // 使用类成员控制器
              decoration: InputDecoration( 
                icon: const Icon(Icons.account_circle), 
                labelText: 'Username', 
              ), 
            ), 
            TextField( 
              controller: passwordController, // 使用类成员控制器
              obscureText: true, 
              decoration: InputDecoration( 
                icon: const Icon(Icons.lock), 
                labelText: 'Password', 
              ), 
            ), 
          ], 
        ), 
        buttons: [ 
          DialogButton( 
            onPressed: () {
              // 这里可以添加登录逻辑,比如将用户名密码保存到Firestore
              Navigator.pop(context);
              // 登录完成后标记验证完成,避免再次弹窗
              setState(() {
                _isVerified = true;
              });
            }, 
            child: const Text( 
              "LOGIN", 
              style: TextStyle(color: Colors.white, fontSize: 20), 
            ), 
          ) 
        ]).show(); 
    } 
  } 

  @override 
  void initState() { 
    super.initState(); 
    // 使用addPostFrameCallback确保组件完全构建后再执行异步验证
    WidgetsBinding.instance.addPostFrameCallback((_) {
      verificarUsuario();
    });
  } 

  @override
  void dispose() {
    // 销毁控制器,避免内存泄漏
    nameController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  @override 
  Widget build(BuildContext context) { 
    return Scaffold( 
      appBar: AppBar( 
        title: const Text("Home"), 
      ), 
      body: Column( 
        mainAxisAlignment: MainAxisAlignment.center, 
        children: [ 
          Container( 
            margin: const EdgeInsets.all(65), 
            width: double.infinity, 
            child: ElevatedButton( 
              style: ElevatedButton.styleFrom( 
                backgroundColor: Colors.red, // Flutter 3.0+ 用backgroundColor替代旧的primary属性
              ), 
              onPressed: salir, 
              child: const Text(
                "Logout",
                style: TextStyle(
                  color:Colors.white,
                  fontSize: 16, 
                  fontWeight: FontWeight.bold
                ),
              ), 
            ), 
          ) 
        ], 
      ), 
    ); 
  } 
}

额外说明

  • 使用WidgetsBinding.instance.addPostFrameCallback包裹验证方法,可以确保在组件完全构建完成后再执行异步操作,避免上下文相关的异常。
  • 在dispose方法中销毁TextEditingController,避免内存泄漏。
  • 登录按钮的回调里添加了标记验证完成的逻辑,这样用户登录后就不会再弹出弹窗了。
  • 针对Flutter 3.0+版本,把按钮样式的primary改为了backgroundColor,这是官方推荐的新写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:27:39