根据对提供值的更改更改 UI

Posted

技术标签:

【中文标题】根据对提供值的更改更改 UI【英文标题】:Change UI based on change to provided value 【发布时间】:2021-01-09 19:13:51 【问题描述】:

如果提供的布尔值 (isLoggedIn) 更改为 true,我想从该屏幕导航到新屏幕。下面的第一个构建方法不可能,因为在构建过程中无法调用 Navigator。我试图在构建中执行此操作,因为我需要访问上下文才能使用我的提供程序。来自 Authorization 提供者的 isLoggedIn 的值可能随时更改,因此我必须对此进行检查。

如何使用提供者和导航器解决这个问题?

//Not working solution
Widget build(BuildContext context) 
  Authorization auth = Provider.of<Authorization>(context);
  return Scaffold(
    body: Center(
        child: auth.isLoggedIn
            ? Text(
                "Logged In",
              )
            : Navigator.pushReplacementNamed(context, 'sign-in')),
  );


 

我可以在没有 Navigator 的情况下这样做:

//Working solution
class SplashScreen extends StatelessWidget 
  static const routeName = 'splash';
  @override
  Widget build(BuildContext context) 
    final auth = Provider.of<Authorization>(context);
    return auth.isLoggedIn ? HomeScreen() : SignInScreen();
  

但如果那是一种可靠的方法,我现在不这样做。

【问题讨论】:

您将 UI 代码与功能代码混合在一起。你不能这样做。如果应该在构建方法之外。您应该检查用户是否已登录,然后导航到另一个视图,或者如果用户未登录,请导航到登录页面。 我知道我必须删除构建方法之外的导航器,正如我在问题中所说的那样。由于我不知道提供的值何时发生变化,您将把这张支票放在哪里? 【参考方案1】:

这是解决问题的方法。

enum AuthStatus 
  NOT_DETERMINED,
  NOT_LOGGED_IN,
  LOGGED_IN,
//Always define this outside the class.


 AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
 @override
  void initState() 
    super.initState();
    getCurrentUser().then((user) 
      setState(() 
        if (user != null) 
          _userId = user?.uid;
         
        
        authStatus =
            user?.uid == null ? AuthStatus.NOT_LOGGED_IN : AuthStatus.LOGGED_IN;
      );
    );
  
Future<FirebaseUser> getCurrentUser() async 
FirebaseUser user = await _firebaseAuth.currentUser();
return user;


  void loginCallback() 
    getCurrentUser().then((user) 
      setState(() 
        _userId = user.uid.toString();
         authStatus = AuthStatus.LOGGED_IN;
        Navigator.of(context).pushReplacementNamed('/');
              );
    );
  
   
   Widget buildWaitingScreen() 
    return Scaffold(
      body: Container(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: CircleAvatar(
                backgroundColor: Colors.transparent,
                radius: 70.0,
                child: Image.asset('assets/icons/icon.png'),
              ),
      ),
    );
  

  @override
  Widget build(BuildContext context) 
    switch (authStatus) 
      case AuthStatus.NOT_DETERMINED:
        return buildWaitingScreen();
        break;
      case AuthStatus.NOT_LOGGED_IN:
        return new LoginSignUpPage();
        break;
      case AuthStatus.LOGGED_IN:
        if (_userId.length > 0 && _userId != null) 
          return new HomePage();
         else
          return buildWaitingScreen();
        break;
      default:
        return buildWaitingScreen();
    
  

在 initState 中使用它来导航

 void loginCallback() 
  getCurrentUser().then((user) 
  setState(() 
    _userId = user.uid.toString();
     authStatus = AuthStatus.LOGGED_IN;
           );); 
   if(authStatus==AuthStatus.LOGGED_IN)
        Navigator.pushReplacementNamed(context, 'sign-in') 

【讨论】:

不推荐使用导航器。我是否应该根据提供的 auth 布尔值的变化返回所需的屏幕? @João Soares 你难道不认为这是 UI 代码和功能代码的混合,这里仍在检查构建方法中的值吗? 这只是该方法的一个示例。这旨在帮助您保持用户登录状态。这样,如果您关闭应用程序,您就不必再次登录。还有另一种选择:我的代码中的 loginCallback() 可以在 initState 中调用以导航用户(如果已登录),否则构建主上下文 好的,在我依赖 BuildContext 从我的提供者那里获取身份验证的情况下,我无法在 initstate 中执行此操作。此外,在您的情况下,initState 可以检查 AuthStatus 的动态变化吗?还是仅在最初调用 initState 时才进行检查?

以上是关于根据对提供值的更改更改 UI的主要内容,如果未能解决你的问题,请参考以下文章