如何在 flutter 中添加全屏加载器

How to add full screen loader in flutter

在这里,我正在尝试添加一个全屏加载器,但它不起作用,我已经完成了完整的代码,但是当我尝试添加一个全屏加载器时,它不起作用。所以在这里我只想在单击登录按钮时添加全屏加载程序。在这段代码中,我已经定义了 _isLoading 变量,当它的真正加载器将被显示时。

这是我试过的代码。

class LoginScreen extends StatefulWidget {
  LoginScreen({Key key}) : super(key: key);

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

class _LoginScreenState extends State<LoginScreen> {
  @override
  Widget build(BuildContext context) {
    final formKey = new GlobalKey<FormState>();
    final _emailFocusNode = new FocusNode();
    final _passwordFocusNode = new FocusNode();

    String _username;
    String _password;
    bool rememberMe = false;
    bool _isLoading = false;

    @override
    void initState() {
      super.initState();
    }

    void _showErrorDialog(String message) {
      showDialog(
          barrierDismissible: false,
          context: context,
          builder: (context) => ShowErrorDialog(
                title: Text('An Error Occurred!'),
                content: Text(message),
              ));
    }

    Widget _buildUserNameField() {
      return EnsureVisibleWhenFocused(
        focusNode: _emailFocusNode,
        child: TudoEmailWidget(
          focusNode: _emailFocusNode,
          prefixIcon: Icon(Icons.email),
          labelText: AppConstantsValue.appConst['login']['email']
              ['translation'],
          validator: (val) => Validators.validateEmail(val.trim()),
          onSaved: (val) => _username = val.trim(),
          // onChanged:(val) => _username = val.trim(),
        ),
      );
    }

    Widget _buildPasswordField() {
      return EnsureVisibleWhenFocused(
        focusNode: _passwordFocusNode,
        child: TudoPasswordWidget(
          focusNode: _passwordFocusNode,
          prefixIcon: Icon(Icons.vpn_key),
          hintText: AppConstantsValue.appConst['login']['password']
              ['translation'],
          labelText: AppConstantsValue.appConst['login']['password']
              ['translation'],
          validator: Validators().validatePassword,
          onSaved: (val) => _password = val.trim(),
        ),
      );
    }

    Widget _buildLoginButton(BuildContext context, LoginViewModel loginVm) {
      return GestureDetector(
        child: TudoLoginButtonWidget.buildRoundedRectButton(
            "Log In", signInGradients, false),
        onTap: () async {
          if (!formKey.currentState.validate()) {
            // Invalid!
            return;
          }
          formKey.currentState.save();
          print("User");

          setState(() {
            _isLoading = true;
          });
          try {
            LoginRepository _loginRepository = LoginRepository();
            Map<String, dynamic> loginResponse =
                await _loginRepository.loginUser(_username, _password);
            if (loginResponse['error'] != null) {
              var errorMessage = 'Invalid email or password';
              _showErrorDialog(errorMessage);
            } else {
              LoginUser userModel = LoginUser(
                token: loginResponse['data']['loginUser']['token'],
                user: User.fromJson(
                  loginResponse['data']['loginUser']['user'],
                ),
              );
              SharedPreferences preferences =
                  await SharedPreferences.getInstance();
              preferences.setString('user', loginUserToJson(userModel));
              loginVm.loginMe(context, userModel);
            }
            setState(() {
              _isLoading = false;
            });
          } catch (error) {
            print('error');
            print(error);
            setState(() {
              _isLoading = false;
            });
            var errorMessage = 'Authentication failed';
            _showErrorDialog(errorMessage);
          }
        },
      );
    }


    Widget content(context, loginVm) {
      ProgressDialog pr =
          new ProgressDialog(context, type: ProgressDialogType.Normal);
      pr.style(message: 'Showing some progress...');
      return new SafeArea(
        top: false,
        bottom: false,
        child: Form(
          key: formKey,
          child: Scrollbar(
            child: SingleChildScrollView(
              dragStartBehavior: DragStartBehavior.down,
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: new Container(
                margin: EdgeInsets.fromLTRB(30, 100, 30, 0),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    TudoLogoWidget(),
                    _buildUserNameField(),
                    SizedBox(
                      height: 20,
                    ),
                    _buildPasswordField(),

                    SizedBox(
                      height: 20.0,
                    ),
                    _buildLoginButton(context, loginVm),
                    SizedBox(
                      height: 20,
                    ),

                  ],
                ),
              ),
            ),
          ),
        ),
      );
    }

    return new WillPopScope(
      onWillPop: () =>
          SystemChannels.platform.invokeMethod('SystemNavigator.pop'),
      child: Scaffold(
        body: Container(
          height: double.infinity,
          width: double.infinity,
          child: Stack(
            children: <Widget>[
              Background(),
              SingleChildScrollView(
                  child: StoreConnector<AppState, LoginViewModel>(
                converter: (Store<AppState> store) =>
                    LoginViewModel.fromStore(store),
                builder: (BuildContext context, LoginViewModel loginVm) =>
                    content(context, loginVm),
              )),
            ],
          ),
        ),
      ),
    );
  }
}

class LoginViewModel {
  final Function(BuildContext context, LoginUser loginUser) loginMe;
  LoginViewModel({
    this.loginMe,
  });

  static LoginViewModel fromStore(Store<AppState> store) {
    return LoginViewModel(
      loginMe: (context, loginUser) {
        store.dispatch(
          login(context, loginUser),
        );
      },
    );
  }
}

我注意到你的构建方法中有很多嵌套的东西。你可以把它们拉出来。

例如,我认为您的 initState() 方法不会在任何时候被调用。

您需要做的是: 只需从现在所在的位置删除该行:

  Widget build(BuildContext context) {

然后像这样添加:

    @override
        Widget build(BuildContext context) {    

// YOU HAVE THIS 

          final normalLoginWidgets = WillPopScope(
            onWillPop: () =>
                SystemChannels.platform.invokeMethod('SystemNavigator.pop'),
            child: Scaffold(
              body: Container(
                height: double.infinity,
                width: double.infinity,
                child: Stack(
                  children: <Widget>[
                    Background(),
                    SingleChildScrollView(
                        child: StoreConnector<AppState, LoginViewModel>(
                          converter: (Store<AppState> store) =>
                              LoginViewModel.fromStore(store),
                          builder: (BuildContext context, LoginViewModel loginVm) =>
                              content(context, loginVm),
                        )),
                  ],
                ),
              ),
            ),
          );

          // THIS IS NEW

          if (_isLoading) {
            return Stack(children: <Widget>[
              normalLoginWidgets,
              loadingWidget()
            ]);
          } else {
            return normalLoginWidgets;
          }
        }

我为 showing/close 加载对话框创建了一个 class。
每当您需要显示全屏加载对话框时,您只需调用该方法即可。

我认为这是非常有效的方法,因为您不需要每次都为对话框编写代码

class ProcessDialog {
  static ProcessDialog _instance = new ProcessDialog.internal();
  static bool _isLoading = false;
  ProcessDialog.internal();
  factory ProcessDialog() => _instance;
  static BuildContext _context;

  static void closeLoadingDialog() {
    if (_isLoading) {
      Navigator.of(_context).pop();
      _isLoading = false;
    }
  }

  static void showLoadingDialog(BuildContext context) async {
    _context = context;
    _isLoading = true;
    await showDialog(
        context: _context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return SimpleDialog(
            elevation: 0.0,
            backgroundColor: Colors.transparent,
            children: <Widget>[
              Center(
                child: CircularProgressIndicator(
                  valueColor:
                      AlwaysStoppedAnimation<Color>(ColorUtils.primaryColor),
                ),
              )
            ],
          );
        });
  }

}
void showWait(context) {
  showDialog(
      context: context,
      child: BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 4.0, sigmaY: 4.0),
          child: Scaffold(
            backgroundColor: Colors.transparent,
            body: Container(
              color: Colors.transparent,
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Container(
                    width: MediaQuery.of(context).size.width,
                    child: CircularProgressIndicator()
                  ),
                  Container(
                    margin: EdgeInsets.symmetric(vertical: 20),
                    child: Text(
                      "LOADING...",
                      style: TextStyle(color: Colors.white),
                    ),
                  )
                ],
              ),
            ),
          )));
}

然后调用 showWait(context);在你的按钮事件中。

您可以使用 EasyLoader package

轻松添加全屏加载器

如何使用它的示例:

  Widget build(BuildContext context) {
   return Scaffold(
   //// Wrap your body in a stack
   body: Stack(
    children: <Widget>[
      Center(
        child: Text("Lorem Ipsum"),
      ),
      //// Put the loader widget at the end of the stack. You can set it to appear based on a boolean. E.g. a loading flag.
      EasyLoader(image: AssetImage('assets/loading.png'),)
    ],
  ),
);

}