根据对提供值的更改更改 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的主要内容,如果未能解决你的问题,请参考以下文章

如何根据常规提交规范对 UI 更改进行分类?

如何根据组合框选择更改 UI

根据滑块的值更改 UI 中的图像

如何根据下拉选择更改 jquery ui 自动完成源

使用类组件时如何根据屏幕大小断点更改Material UI Button组件的prop

使用 Jquery UI Datepicker 重定向到 URL:根据所选日期更改 URL 值