3

我正在尝试使用 Firebase 数据来使用 Getx 路由不同的页面。首先我有一个闪屏,想根据条件自动转到不同的页面。如果用户已经登录,它将重定向主页,如果不是登录页面的路由。但是我不能在无状态小部件上使用 initState(),因为我使用 Getx,我不想要有状态小部件。

    class SplashPage extends StatelessWidget {
  RxBool isloading = true.obs;

  @override
  Widget build(BuildContext context) {
    String Uid = "";
    return isloading.value
        ? SpinKitThreeInOut(
            color: Colors.red,
          )
        : Obx(() {
            return Get.find<AuthController>().user != null
                ? homeMethod()
                : login();
          });
  }

  Widget homeMethod() {
    return Home(AuthController.instance.user.toString());
    isloading.value = false;
  }
}

但我无法覆盖 isloading.value = false;

我的 Getx 身份验证控制器:

class AuthController extends GetxController {
  static AuthController instance = Get.find();
  FirebaseAuth auth = FirebaseAuth.instance;
  Rxn<User> _firebaseUser = Rxn<User>();
  String? get user => _firebaseUser.value?.uid;

  @override
  void onReady() {
    // TODO: implement onReady
    super.onReady();
    _firebaseUser.value = auth.currentUser;
    _firebaseUser.bindStream(auth.userChanges());
    ever(_firebaseUser, _initialScreen);
  }
/*  @override
  void onInit() {
    _firebaseUser.bindStream(_auth.authStateChanges());
  }*/

  _initialScreen(User? user) {
    if (user == null) {
      Get.offAll(login());
    } else {
      String userId = user.uid;
      Get.offAll(Home(userId));
    }
  }

  Future<User?> LogInAccounts(String Email, String Password) async {
    FirebaseAuth auth = FirebaseAuth.instance;
    try {
      User? user = (await auth.signInWithEmailAndPassword(
              email: Email, password: Password))
          .user;
      if (user != null) {
        Fluttertoast.showToast(msg: "Account Create Sucessfully");
        return user;
      } else {
        Fluttertoast.showToast(msg: "Account Create Failed!");
        return user;
      }
    } catch (e) {
      return null;
    }
  }
}
4

1 回答 1

0

更新的答案

您可以使用bindStream并这样做,但不是试图将您的User对象转换为流,而是可以使用简单的RxBool. Firebase 已经提供了监听身份验证状态变化的功能。


class AuthController extends GetxController {
  RxBool loggedIn = false.obs;
  @override
  void onInit() {
    super.onInit();
    _subscribe();
  }

  void _subscribe() {
    FirebaseAuth.instance.authStateChanges().listen((User? user) {
      if (user == null) {
        loggedIn(false);
        log('User is currently signed out');
      } else {
        loggedIn(true);
        log('User is signed in');
      }
    });
  }
}

然后,您可以将另外几个方法添加到您的 GetX 类。

  void initNaviationListener() {
    /// inital startup naviation
    _navigateBasedOnLogin();

    /// future navigation based on auth state changes
    ever(loggedIn, (value) {
      _navigateBasedOnLogin();
    });
  }

  void _navigateBasedOnLogin() {
    if (loggedIn.value == false) {
      Get.offAndToNamed(LoginPage.id);
    } else {
      Get.offAndToNamed(HomePage.id);
    }
  }

然后你initNaviationListener可以调用onReadyGetMaterialApp

GetMaterialApp(
        /// onReady is called after GetMaterialApp is fully initialized
        onReady: () => Get.find<AuthController>().initNaviationListener(),
        theme: ThemeData.dark(),
        initialRoute: LoginPage.id,
        getPages: [
          GetPage(
            name: SplashPage.id,
            page: () => SplashPage(),
          ),
          GetPage(
            name: HomePage.id,
            page: () => HomePage(),
          ),
          GetPage(
            name: LoginPage.id,
            page: () => LoginPage(),
          ),
        ],
      )

这将在应用程序启动时导航到相应的屏幕,并响应未来身份验证状态的任何变化。

原始答案

您不必SplashPage从控制器中进行导航。

假设你的GetMaterialApp样子是这样的。这将带你到SplashPage第一个。

GetMaterialApp(
        initialRoute: SplashPage.id,
        getPages: [
          GetPage(
            name: SplashPage.id,
            page: () => SplashPage(),
          ),
          GetPage(
            name: HomePage.id,
            page: () => HomePage(),
          ),
          GetPage(
            name: LoginPage.id,
            page: () => LoginPage(),
          ),
        ],
      )

然后检查登录状态并从您的AuthController.

class AuthController extends GetxController {
  @override
  void onInit() {
    super.onInit();
    _navigateBasedOnLogin();
  }

  Future<void> _navigateBasedOnLogin() async {
    final loggedIn = await _isLoggedIn();

    if (loggedIn) {
      Get.offAndToNamed(HomePage.id); // offAndToNamed will remove the SplashScreen from the navigation stack
    } else {
      Get.offAndToNamed(LoginPage.id);
    }
  }

  Future<bool> _isLoggedIn() async {
    /// run your code to check logged in status and return true or false
  }
}

AuthController然后在你的主目录中初始化。

void main() async {
  Get.put(AuthController());

  runApp(MyApp());
}

通过此设置,您SplashScreen可以成为具有零逻辑的通用加载屏幕。

于 2022-02-22T04:46:09.047 回答