等待API响应时显示加载指示器

时间:2019-09-25 07:15:49

标签: flutter flutter-layout

所以我有一个注册页面,注册功能很好用。 现在,我只需要按一下“注册”按钮后的加载指示器即可。
我已经混合了所有可以想到的要在google中搜索的关键字,并且已经尝试了所有关键字,但无济于事。

这是我尝试过的事情:

使用 FutureBuilder

RaisedButton(
                    onPressed: () async {
                      FutureBuilder<http.Response>(
                        future: registerUser(),
                        builder: (context, snapshot) {
                          if (snapshot.hasData) {
                            return Text("SUCCESS");
                          }
                          if (snapshot.hasError) {
                            return Text("ERROR");
                          }
                          return new Center(
                              child: new CircularProgressIndicator());
                        },
                      );
                    },
                    color: Color(colorPrimary),
                    shape: RoundedRectangleBorder(
                        borderRadius: new BorderRadius.circular(30.0)),
                    child: Text("SignUp"),
                  )

在此方法中,方法被调用,但指示器未显示

使用库 progress_hud : 我认为这是可行的,但是即使我将其放在Center小部件中, 它仍然会转到屏幕底部,并显示overlapping with pixels错误。

还有其他更好的解决方案吗?还是应该只找到一种解决此重叠错误的方法?

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

请使用软件包modal_progress_hud https://pub.dev/packages/modal_progress_hud
ModalProgressHUD必须作为第一个孩子放在脚手架下
我的工作代码段

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ModalProgressHUD(
        inAsyncCall: _isLoading,
        child: SingleChildScrollView(
          child: Container(
               ...

完整的示例代码

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginPage(
        onSignIn: () => print('login successful!'),
      ),
    );
  }
}

class LoginPage extends StatefulWidget {
  final VoidCallback _onSignIn;

  LoginPage({@required onSignIn})
      : assert(onSignIn != null),
        _onSignIn = onSignIn;

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

class _LoginPageState extends State<LoginPage> {
  // maintains validators and state of form fields
  final GlobalKey<FormState> _loginFormKey = GlobalKey<FormState>();

  // manage state of modal progress HUD widget
  bool _isInAsyncCall = false;

  bool _isInvalidAsyncUser = false; // managed after response from server
  bool _isInvalidAsyncPass = false; // managed after response from server

  String _username;
  String _password;
  bool _isLoggedIn = false;

  // validate user name
  String _validateUserName(String userName) {
    if (userName.length < 8) {
      return 'Username must be at least 8 characters';
    }

    if (_isInvalidAsyncUser) {
      // disable message until after next async call
      _isInvalidAsyncUser = false;
      return 'Incorrect user name';
    }

    return null;
  }

  // validate password
  String _validatePassword(String password) {
    if (password.length < 8) {
      return 'Password must be at least 8 characters';
    }

    if (_isInvalidAsyncPass) {
      // disable message until after next async call
      _isInvalidAsyncPass = false;
      return 'Incorrect password';
    }

    return null;
  }

  void _submit() {
    if (_loginFormKey.currentState.validate()) {
      _loginFormKey.currentState.save();

      // dismiss keyboard during async call
      FocusScope.of(context).requestFocus(new FocusNode());

      // start the modal progress HUD
      setState(() {
        _isInAsyncCall = true;
      });

      // Simulate a service call
      Future.delayed(Duration(seconds: 1), () {
        final _accountUsername = 'username1';
        final _accountPassword = 'password1';
        setState(() {
          if (_username == _accountUsername) {
            _isInvalidAsyncUser = false;
            if (_password == _accountPassword) {
              // username and password are correct
              _isInvalidAsyncPass = false;
              _isLoggedIn = true;
            } else
              // username is correct, but password is incorrect
              _isInvalidAsyncPass = true;
          } else {
            // incorrect username and have not checked password result
            _isInvalidAsyncUser = true;
            // no such user, so no need to trigger async password validator
            _isInvalidAsyncPass = false;
          }
          // stop the modal progress HUD
          _isInAsyncCall = false;
        });
        if (_isLoggedIn)
          // do something
          widget._onSignIn();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Modal Progress HUD Demo'),
        backgroundColor: Colors.blue,
      ),
      // display modal progress HUD (heads-up display, or indicator)
      // when in async call
      body: ModalProgressHUD(
        child: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(16.0),
            child: buildLoginForm(context),
          ),
        ),
        inAsyncCall: _isInAsyncCall,
        // demo of some additional parameters
        opacity: 0.5,
        progressIndicator: CircularProgressIndicator(),
      ),
    );
  }

  Widget buildLoginForm(BuildContext context) {
    final TextTheme textTheme = Theme.of(context).textTheme;
    // run the validators on reload to process async results
    _loginFormKey.currentState?.validate();
    return Form(
      key: this._loginFormKey,
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextFormField(
              key: Key('username'),
              decoration: InputDecoration(
                  hintText: 'enter username', labelText: 'User Name'),
              style: TextStyle(fontSize: 20.0, color: textTheme.button.color),
              validator: _validateUserName,
              onSaved: (value) => _username = value,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextFormField(
              key: Key('password'),
              obscureText: true,
              decoration: InputDecoration(
                  hintText: 'enter password', labelText: 'Password'),
              style: TextStyle(fontSize: 20.0, color: textTheme.button.color),
              validator: _validatePassword,
              onSaved: (value) => _password = value,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(32.0),
            child: RaisedButton(
              onPressed: _submit,
              child: Text('Login'),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: _isLoggedIn
                ? Text(
              'Login successful!',
              key: Key('loggedIn'),
              style: TextStyle(fontSize: 20.0),
            )
                : Text(
              'Not logged in',
              key: Key('notLoggedIn'),
              style: TextStyle(fontSize: 20.0),
            ),
          ),
        ],
      ),
    );
  }
}

enter image description here

答案 1 :(得分:0)

FutureBuilder将其生成的主体放在其附加的小部件中。 否则,返回的Widget会去哪里?

材料脚手架示例

Scaffold(
  appBar:AppBar(),
  body: FutureBuilder(
   future: registerUser(),
   builder: (context,snapshot){
    //...
   }
  )
)

问题是,您的未来必然会紧迫RaisedButton。 其次,您可能最好使用StreamBuilder,因为FutureBuilder会在build方法中立即调用它的未来。 因此,改为调用BLoC / ViewModel / wathever以执行registerUser()。 让registerUser()返回一个Future<void>(并将结果内部添加到Stream中)。 然后观察Stream的结果或错误。 对于Streams / Sinks,可以使用StreamController<T>

//In your form Widget

RaisedButton(
 onPressed: registerUser()
)

//In your Widget/BLoC/ViewModel
//Note that the Future can finish with errors from the http call
//call registerUser() with an onError callback to catch these.
//And the Stream can finish with errors(although this is unlikely here)
//the Stream.listen() can also have an onError callback 

Future<void> registerUser() async {
 var result = await http.post();

 //then finally pass it to the stream
 _stream.add(result);
}

答案 2 :(得分:0)

请使用包progress_dialog https://pub.dev/packages/progress_dialog

以下是我的工作代码片段。

pub.yaml

import 'package:fluttertoast/fluttertoast.dart';
import 'package:progress_dialog/progress_dialog.dart';
ProgressDialog progressDialog;

showProgress(BuildContext context, String message, bool isDismissible) async {
  progressDialog = new ProgressDialog(context,
      type: ProgressDialogType.Normal, isDismissible: isDismissible);
  progressDialog.style(
      message: message,
      borderRadius: 10.0,
      backgroundColor: Color(COLOR_PRIMARY),
      progressWidget: Container(
          padding: EdgeInsets.all(8.0),
          child: CircularProgressIndicator(
            backgroundColor: Colors.white,
          )),
      elevation: 10.0,
      insetAnimCurve: Curves.easeInOut,
      messageTextStyle: TextStyle(
          color: Colors.white, fontSize: 19.0, fontWeight: FontWeight.w600));
  await progressDialog.show();
}

updateProgress(String message) {
  progressDialog.update(message: message);
}

hideProgress() async {
  if(progressDialog!=null)
  await progressDialog.hide();
}

helper.dart

import 'package:mygame/services/helper.dart';
... 
RaisedButton(
                    onPressed: () async {
                      showProgress(context, 'Registering user, please wait...', true);
                      await registerUser().then((result) {
                        hideProgress();
                        pushAndRemoveUntil(context, HomePage(), false);
                      }).catchError((error) {
                        hideProgress();
                        Fluttertoast.showToast(
                            msg: "Signup failed:"+error.toString(),
                            toastLength: Toast.LENGTH_LONG,
                            gravity: ToastGravity.CENTER,
                            timeInSecForIosWeb: 1,
                            backgroundColor: Colors.green.shade700,
                            textColor: Colors.white,
                            fontSize: 16.0
                        );
                        print('Registration Error: $error');
                      });
                    },
                    color: Color(colorPrimary),
                    shape: RoundedRectangleBorder(
                        borderRadius: new BorderRadius.circular(30.0)),
                    child: Text("SignUp"),
                  )

登录.dart

df1 = pd.DataFrame({ 
    'Product': ['AA', 'AA', 'BB', 'BB', 'BB'],
    'Col1': [1, 2, 1, 2, 3], 
    'Col2': [2, 4, 2, 4, 6]})
print(df1)
df2 = pd.DataFrame({
    'FX Rate': [1.5, 2.0, 3.0, 5.0, 10.0]})
print(df2)

df1 = df1.reset_index(drop=True)
df2 = df2.reset_index(drop=True)

for col in ['Col1', 'Col2']:
    df1[col] = df1[col] * df2['FX Rate']
df1
(df1)
  Product  Col1  Col2
0      AA     1     2
1      AA     2     4
2      BB     1     2
3      BB     2     4
4      BB     3     6

(df2)
   FX Rate
0      1.5
1      2.0
2      3.0
3      5.0
4     10.0

Out[1]: 
  Product  Col1  Col2
0      AA   1.5   3.0
1      AA   4.0   8.0
2      BB   3.0   6.0
3      BB  10.0  20.0
4      BB  30.0  60.0