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

Flutter登录按钮点击后状态未触发,页面不跳转问题求助

问题:登录成功后页面不自动跳转,需手动刷新

所有功能正常,但点击登录按钮后,用户已成功登录,但页面不会自动切换到登录后的界面,必须手动刷新才会更新状态,使用setState也无法解决。


Root页面代码

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';

class Root extends StatefulWidget {
  const Root({Key? key}) : super(key: key);

  @override
  State<Root> createState() => _RootState();
}

enum AuthState { signedIn, signedOut }

class _RootState extends State<Root> {
  AuthState _authState = AuthState.signedOut;
  AuthService auth = AuthService();
  String authuser = "ghnfgjy";

  void signOut() async {
    await auth.signOut();
    setState(() {
      _authState = AuthState.signedOut;
    });
  }

  void signIn() async {
    setState(() {
      _authState = AuthState.signedIn;
    });
  }

  @override
  void initState() {
    super.initState();
    auth.currentUser().then((user) {
      print("check check $user  ");
      setState(() {
        _authState = user == null ? AuthState.signedOut : AuthState.signedIn;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_authState == AuthState.signedOut) {
      return Login();
    } else {
      return Scaffold(
          body: Center(
        child: Column(
          children: [
            SizedBox(
              height: 69,
            ),
            Text("Helllloooooooo $authuser"),
            SizedBox(
              height: 45,
            ),
            FlatButton(
                onPressed: () {
                  signOut();
                },
                child: Text("Sign out"))
          ],
        ),
      ));
    }
  }
}

Login页面代码

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
import 'package:login/share/constant.dart';

class Login extends StatefulWidget {
  const Login({Key? key}) : super(key: key);

  @override
  _LoginState createState() => _LoginState();
}

enum FormType {
  login,
  register,
}

class _LoginState extends State<Login> {
  dynamic _email;
  dynamic _password;
  final formkey = GlobalKey<FormState>();
  FormType _formType = FormType.login;
  dynamic result;
  AuthService auth = AuthService();

  bool validateandsave() {
    final form = formkey.currentState;
    if (form!.validate()) {
      form.save();
      print('form is valid');
      print('$_email $_password');
      return true;
    } else {
      print('form is not valid');
      return false;
    }
  }

  Future validateandsumit() async {
    if (validateandsave()) {
      if (_formType == FormType.register) {
        auth.register(_email, _password);
        setState(() {
          _formType = FormType.login;
        });
      } else {
        auth.signIn(_email, _password);
      }
    }
  }

  void moveToRegister() {
    formkey.currentState!.reset();
    setState(() {
      _formType = FormType.register;
    });
  }

  void moveToLogin() {
    formkey.currentState!.reset();
    setState(() {
      _formType = FormType.login;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: const LinearGradient(
            begin: Alignment.topRight,
            end: Alignment.bottomLeft,
            colors: [
              Colors.blueAccent,
              Colors.purple,
            ],
          ),
        ),
        padding: EdgeInsets.all(16),
        child: Form(
          key: formkey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.center,
            children: openText() + inputFields() + buttons(),
          ),
        ),
      ),
    );
  }

  List<Widget> openText() {
    if (_formType == FormType.register) {
      return [
        Text(
          'Please Register to continue',
          style: TextStyle(
              fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
          textAlign: TextAlign.center,
        ),
        SizedBox(
          height: 40,
        ),
      ];
    } else {
      return [
        Text('Please Login to continue',
            style: TextStyle(
                fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
            textAlign: TextAlign.center),
        SizedBox(
          height: 40,
        ),
      ];
    }
  }

  List<Widget> inputFields() {
    return [
      TextFormField(
          decoration: inputDecoration.copyWith(
            labelText: 'Email Address',
          ),
          style: TextStyle(color: Colors.black),
          validator: (val) => val!.isEmpty ? 'Enter the email address' : null,
          onSaved: (val) => _email = val),
      SizedBox(
        height: 20,
      ),
      TextFormField(
          obscureText: true,
          decoration: inputDecoration.copyWith(
            labelText: 'Password',
          ),
          style: TextStyle(color: Colors.black),
          validator: (val) => val!.isEmpty ? 'Enter the password' : null,
          onSaved: (val) => _password = val),
      SizedBox(
        height: 60,
      ),
    ];
  }

  List<Widget> buttons() {
    if (_formType == FormType.register) {
      return [
        FlatButton(
          padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
          onPressed: validateandsumit,
          child: Text(
            'Register',
            style: TextStyle(fontSize: 20, color: Colors.white),
          ),
          color: Colors.pinkAccent,
        ),
        SizedBox(
          height: 20,
        ),
        FlatButton(
          padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
          onPressed: moveToLogin,
          child: Text(
            'Have an account? Login',
            style: TextStyle(fontSize: 20, color: Colors.white),
          ),
          color: Colors.pinkAccent,
        ),
      ];
    } else {
      return [
        FlatButton(
          padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
          onPressed: validateandsumit,
          child: Text(
            'Login',
            style: TextStyle(fontSize: 20, color: Colors.white),
          ),
          color: Colors.pinkAccent,
        ),
        SizedBox(
          height: 20,
        ),
        FlatButton(
          padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
          onPressed: moveToRegister,
          child: Text(
            'Register',
            style: TextStyle(fontSize: 20, color: Colors.white),
          ),
          color: Colors.pinkAccent,
        ),
      ];
    }
  }
}

AuthService代码

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class AuthService {
  FirebaseAuth _auth = FirebaseAuth.instance;

  //Stream <User>? get authStateChanges => _auth.authStateChanges();
  Stream<User?> get authStateChanges => _auth.authStateChanges();
  CollectionReference users = FirebaseFirestore.instance.collection('users');
  late User user;

  //register in with email and password
  Future register(email, password) async {
    try {
      UserCredential userCredential = await _auth
          .createUserWithEmailAndPassword(email: email, password: password);
      user = userCredential.user!;
      print('Registered ${user.uid}');

      var userdata = {
        'email': email,
        'password': password,
        'role': 'user',
      };

      users.doc(user.uid).get().then((doc) {
        if (doc.exists) {
          doc.reference.update(userdata);
        } else {
          users.doc(user.uid).set(userdata);
        }
      });
    } catch (e) {
      print(e);
    }
  }

  //sign in with email and password
  Future signIn(email, password) async {
    try {
      UserCredential userCredential = await _auth.signInWithEmailAndPassword(
          email: email, password: password);
      user = userCredential.user!;
      print('logged in ${user.uid}');

      var userdata = {
        'email': email,
        'password': password,
        'role': 'user',
      };

      users.doc(user.uid).get().then((doc) {
        if (doc.exists) {
          doc.reference.update(userdata);
        } else {
          users.doc(user.uid).set(userdata);
        }
      });
    } catch (e) {
      print(e);
    }
  }

  Future currentUser() async {
    try {
      User user = await _auth.currentUser!;
      return user.uid;
    } catch (e) {
      print(e);
    }
  }

  //sign out
  Future signOut() async {
    try {
      await _auth.signOut();
    } catch (e) {
      print(e);
    }
  }
}

解决方案

问题根源在于Root页面只在initState时检查一次用户登录状态,登录操作完成后没有触发状态更新。正确的做法是监听Firebase Auth的状态流,实时更新UI。

修改Root页面代码:

  1. 移除initState中的单次检查,改为监听auth.authStateChanges流
  2. 订阅流并在状态变化时更新_authState

修改后的_RootState代码:

class _RootState extends State<Root> {
  AuthState _authState = AuthState.signedOut;
  AuthService auth = AuthService();
  String authuser = "ghnfgjy";
  StreamSubscription? _authSubscription;

  void signOut() async {
    await auth.signOut();
  }

  @override
  void initState() {
    super.initState();
    // 监听Auth状态变化
    _authSubscription = auth.authStateChanges.listen((User? user) {
      setState(() {
        _authState = user == null ? AuthState.signedOut : AuthState.signedIn;
        if (user != null) {
          authuser = user.uid; // 更新用户ID
        }
      });
    });
  }

  @override
  void dispose() {
    _authSubscription?.cancel(); // 页面销毁时取消订阅,避免内存泄漏
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_authState == AuthState.signedOut) {
      return Login();
    } else {
      return Scaffold(
          body: Center(
        child: Column(
          children: [
            SizedBox(
              height: 69,
            ),
            Text("Helllloooooooo $authuser"),
            SizedBox(
              height: 45,
            ),
            FlatButton(
                onPressed: signOut,
                child: Text("Sign out"))
          ],
        ),
      ));
    }
  }
}

额外优化点:

  • signOut方法中无需手动调用setState,因为监听流会自动捕获登出状态
  • 更新authuser为当前登录用户的UID,避免固定字符串
  • 添加流订阅的取消操作,防止内存泄漏

这样修改后,登录/登出操作完成后,Auth状态流会自动触发setState,页面会实时刷新,无需手动刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 23:36:17