26

I have a login form with two textfields 'UserName', 'Password' & a button 'Login'. On tap of login button I am calling an API. I want to show a CircularProgressIndicator during this api call. Progress dialog should show in the centre & top of login form. I have tried FutureBuilder but it hides the login form shows CircularProgressIndicator only. I want all content of screen to show behind the CircularProgressIndicator.

Full Code:

import 'package:flutter/material.dart';
import 'package:the_don_flutter/userModel.dart';
import 'package:validate/validate.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'signup.dart';

class Login extends StatefulWidget{
  @override
  State<Login> createState() {
    // TODO: implement createState
    return LoginFormState();
  }
}

class LoginFormState extends State<Login>{

  final GlobalKey<FormState> formKey = new GlobalKey<FormState>();

  String _passwordValidation(String value){
    if(value.isEmpty){
      return "Field Can't be empty.";
    }else if(value.length < 6)
      return "Password must be of six characters long.";
    return null;
  }

  String _checkValidEmail(String value){
    try{
      Validate.isEmail(value);
    }catch(e){
      return "Email is not valid.";
    }
    return null;
  }

  Future<User> _loginUser() async{
    var response = await http.post("https://example/public/api/login", headers: {}, body: {'username':'poras@techaheadcorp.com', 'password':'123456'})
        .catchError((error) => print("Error $error"));
    print("response of login ${response.body}");
    return User.fromJson(json.decode(response.body));
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: Container(
        padding: EdgeInsets.only(left: 20.0, top: 100.0, right: 20.0),
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("assets/images/bg_green.jpg"),
                fit: BoxFit.fill)),
        child: Column(
          children: <Widget>[

            Form(
              key: formKey,
              child: Column(children: <Widget>[
                Padding(padding: EdgeInsets.only(bottom: 20.0),
                  child: TextFormField(
                    validator: _checkValidEmail,
                    decoration: InputDecoration(
                        hintText: "abc@example.com",
                        labelText: "User Name",
                        hintStyle: TextStyle(color: Colors.white)),
                    style: TextStyle(color: Colors.white),
                    autofocus: true,),),
                TextFormField(
                  obscureText: true,
                  validator: _passwordValidation,
                  decoration: InputDecoration(
                      hintText: "password",
                      labelText: "Password",
                      hintStyle: TextStyle(color: Colors.white)),
                  style: TextStyle(color: Colors.white),
                  autofocus: true,)
              ],),),
            Padding(padding: EdgeInsets.only(top: 20.0),
              child: Row(mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  Text("Forgot Password?", textAlign: TextAlign.start, style: TextStyle(color: Colors.white,),),
                ],),),
            Padding(padding: EdgeInsets.only(top: 20.0),
              child: GestureDetector(
                onTap: _submitForm,
                child: Row(mainAxisAlignment: MainAxisAlignment.end,
                  children: <Widget>[
                    Text("LOGIN", textAlign: TextAlign.start, style: TextStyle(color: Colors.white, fontSize: 40.0),),
                    Icon(Icons.chevron_right, size: 40.0, color: Colors.white,),
                  ],),), ),

            Expanded(
                child: Padding(padding: EdgeInsets.only(bottom: 20.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: <Widget>[
                      Text("Don't have an account?", textAlign: TextAlign.start, style: TextStyle(color: Colors.white,),),
                      Container(
                          margin: EdgeInsets.only(left: 8.0),
                          child: GestureDetector(
                            onTap: (){Navigator.push(context, MaterialPageRoute(builder: (context) => Signup()));},
                            child: Text("REGISTER NOW!", textAlign: TextAlign.start, style: TextStyle(color: Colors.black,),),
                          )),
                    ],
                  ),))
          ],
        ),
      ),
    );
  }

  _submitForm() {
    if(formKey.currentState.validate()){
      print("Go to Home page");
      _loginUser();
    }
  }

}
Quick learner
  • 10,632
  • 4
  • 45
  • 55
Poras Bhardwaj
  • 1,073
  • 1
  • 15
  • 33
  • 1
    Have you looked at https://stackoverflow.com/questions/47065098/how-work-with-progress-indicator-in-flutter? – Romain Rastel Jul 19 '18 at 06:15
  • How about doing something like [this](https://stackoverflow.com/questions/43550853/how-do-i-do-the-frosted-glass-effect-in-flutter)? instead of flutter image you can have circular progress indicatory – Dhaval Shah Jul 19 '18 at 08:09

5 Answers5

53

To show a progressdialog on button click while api is fetching data on login screen.

Try this

Declare this method to show a progress dialog

showLoaderDialog(BuildContext context){
    AlertDialog alert=AlertDialog(
      content: new Row(
        children: [
          CircularProgressIndicator(),
          Container(margin: EdgeInsets.only(left: 7),child:Text("Loading..." )),
        ],),
    );
    showDialog(barrierDismissible: false,
      context:context,
      builder:(BuildContext context){
        return alert;
      },
    );
  }

USAGE

on button click when api is called, call this method like this

onPressed: () {
                showLoaderDialog(context);
                //api here },

and when response is fetched dismiss that dialog like this

Navigator.pop(context);
Quick learner
  • 10,632
  • 4
  • 45
  • 55
13

This demo (with source code) should be very close to what your trying to do

enter image description here

It includes triggering the form validators before and after the async call.

https://pub.dartlang.org/packages/modal_progress_hud

mmccabe
  • 2,259
  • 1
  • 24
  • 25
7

create something like bool _isLoading = false;

When the sign-in button is pressed then

onPressed: (){
  setState(() {
      _isLoading = true;
  });
}

Meanwhile, use Stack to insert the CircularProgressIndicator

Stack(children: <Widget>[
   _isLoading ? CircularProgressIndicator() : Container(), //only show CircularProgressIndicator when loading
   //your login body here
Dat Tran
  • 357
  • 3
  • 8
6

You can try below code snippet for it

class ProgressHUD extends StatelessWidget {

  final Widget child;
  final bool inAsyncCall;
  final double opacity;
  final Color color;
  final Animation<Color> valueColor;

  ProgressHUD({
    Key key,
    @required this.child,
    @required this.inAsyncCall,
    this.opacity = 0.3,
    this.color = Colors.grey,
    this.valueColor,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Widget> widgetList = new List<Widget>();
    widgetList.add(child);
    if (inAsyncCall) {
      final modal = new Stack(
        children: [
          new Opacity(
            opacity: opacity,
            child: ModalBarrier(dismissible: false, color: color),
          ),
          new Center(
            child: new CircularProgressIndicator(
              valueColor: valueColor,
            ),
          ),
        ],
      );
      widgetList.add(modal);
    }
    return Stack(
      children: widgetList,
    );
  }
}

Use it

 body: ProgressHUD(
          child: screen,
          inAsyncCall: _isLoading,
          opacity: 0.0,
        ),

just change the state of _isloading true if you want to display progress.

Sunil
  • 3,211
  • 3
  • 21
  • 21
4

where ever you want call this function

  progressDialogue(BuildContext context) {
  //set up the AlertDialog
  AlertDialog alert = AlertDialog(
    backgroundColor: Colors.transparent,
    elevation: 0,
    content: Container(
      child: Center(
        child: CircularProgressIndicator(),
      ),
    ),
  );
  showDialog(
    //prevent outside touch
    barrierDismissible: false,
    context: context,
    builder: (BuildContext context) {
      //prevent Back button press
      return WillPopScope(onWillPop: () async => false, child: alert);
    },
  );
}

**For dismiss call this **

Navigator.pop(context);
Ilyas Arafath
  • 511
  • 7
  • 13