Flutter - How can I add a circular loading indicator to my button?
Asked Answered
B

4

21

I have a Flutter code. instead of showing nothing when the submit button is clicked, I want to show the circular loading indicator when the button is clicked so to keep the user busy but I'm having a challenge to convert a tutorial I have that does that to a work with my code.

Here is the tutorial:

...
 children: <Widget>[
            new Padding(
              padding: const EdgeInsets.all(16.0),
              child: new MaterialButton(
                child: setUpButtonChild(),
                onPressed: () {
                  setState(() {
                    if (_state == 0) {
                      animateButton();
                    }
                  });
                },
                elevation: 4.0,
                minWidth: double.infinity,
                height: 48.0,
                color: Colors.lightGreen,
              ),
            )
          ],
 Widget setUpButtonChild() {
    if (_state == 0) {
      return new Text(
        "Click Here",
        style: const TextStyle(
          color: Colors.white,
          fontSize: 16.0,
        ),
      );
    } else if (_state == 1) {
      return CircularProgressIndicator(
        valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
      );
    } else {
      return Icon(Icons.check, color: Colors.white);
    }
  }

  void animateButton() {
    setState(() {
      _state = 1;
    });

    Timer(Duration(milliseconds: 1000), () {
      setState(() {
        _state = 2;
      });
    });

    Timer(Duration(milliseconds: 3300), () {
       Navigator.of(context).push(
        MaterialPageRoute(
          builder: (context) => AnchorsPage(),
        ),
      );
    });
  }

Here's my code. All I want to do is to display the CircularProgressIndicator when the system is performing the HTTP request.

And here is my code where I want to use the CircularProgressIndicator:

                           Center(

                            child: 
                            RaisedButton(
                              padding: EdgeInsets.fromLTRB(80, 10, 80, 10),
                              color: Colors.green,
                             
                              child: setUpButtonChild(),
                             
                              onPressed: ()  {

                                setState(()async {
                                _state = 1;
                                var toSubmit = {
                                  "oid": EopOid,
                                  "modifiedBy": user['UserName'].toString(),
                                  "modifiedOn": DateTime.now().toString(),
                                  "submitted": true,
                                  "submittedOn": DateTime.now().toString(),
                                  "submittedBy": user['UserName'].toString()
                                };
                                for (EopLine i in selectedEops) {
                                  var item = {
                                    "oid": i.oid.toString(),
                                    "quantityCollected": i.quantityCollected,
                                    "modifiedBy": user['UserName'].toString(),
                                    "modifiedOn": DateTime.now().toString(),
                                  };
                                  await http
                                      .put(
                                          "http://api.ergagro.com:112/UpdateEopLine",
                                          headers: {
                                            'Content-Type': 'application/json'
                                          },
                                          body: jsonEncode(item))
                                      .then((value) async {
                                    if (selectedEops.indexOf(i) ==
                                        selectedEops.length - 1) {
                                      await http
                                          .put(
                                              "http://api.ergagro.com:112/SubmitEop",
                                              headers: {
                                                'Content-Type':
                                                    'application/json'
                                              },
                                              body: jsonEncode(toSubmit))
                                          .then((value) {
                                        print('${value.statusCode} submitted');
                                        Navigator.pop(context);
                                      });
                                    }
                                  });
                                }
                               _state = 2;
                                });
                              //Navigator.of(context).push(MaterialPageRoute(
                              //builder: (context) =>
                              //StartScanPage(widget.dc_result)));
                              },
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(50),
                              ),
                            ),
                          ),

Bernicebernie answered 3/8, 2020 at 18:13 Comment(0)
D
36

If you're using a button with the icon() constructor (icon + text), you can swap the icon with the CircularProgressIndicator when the button state changes. It works because both the icon and the indicator are widgets:

return ElevatedButton.icon(
  onPressed: _isLoading ? null : _onSubmit,
  style: ElevatedButton.styleFrom(padding: const EdgeInsets.all(16.0)),
  icon: _isLoading
      ? Container(
          width: 24,
          height: 24,
          padding: const EdgeInsets.all(2.0),
          child: const CircularProgressIndicator(
            color: Colors.white,
            strokeWidth: 3,
          ),
        )
      : const Icon(Icons.feedback),
  label: const Text('SUBMIT'),
);

Live Demo

Disapprove answered 3/10, 2021 at 11:29 Comment(2)
But how to place icon to right end side ?)Jahncke
@FəqanÇələbizadə Just swap the icon with the label widget. See this answer for more examples.Disapprove
B
10

You can copy paste run full code below
You can directly use package https://pub.dev/packages/progress_indicator_button
or reference it's source code
You can pass AnimationController to http job and use controller.forward and reset

code snippet

void httpJob(AnimationController controller) async {
    controller.forward();
    print("delay start");
    await Future.delayed(Duration(seconds: 3), () {});
    print("delay stop");
    controller.reset();
  }
...  
ProgressButton(
        borderRadius: BorderRadius.all(Radius.circular(8)),
        strokeWidth: 2,
        child: Text(
          "Sample",
          style: TextStyle(
            color: Colors.white,
            fontSize: 24,
          ),
        ),
        onPressed: (AnimationController controller) async {
          await httpJob(controller);
        }

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'package:progress_indicator_button/progress_button.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void httpJob(AnimationController controller) async {
    controller.forward();
    print("delay start");
    await Future.delayed(Duration(seconds: 3), () {});
    print("delay stop");
    controller.reset();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              width: 200,
              height: 60,
              child: ProgressButton(
                borderRadius: BorderRadius.all(Radius.circular(8)),
                strokeWidth: 2,
                child: Text(
                  "Sample",
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 24,
                  ),
                ),
                onPressed: (AnimationController controller) async {
                  await httpJob(controller);
                },
              ),
            ),
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
Blaise answered 4/8, 2020 at 9:30 Comment(0)
B
10

You can also use ternary operator to output based on some _isLoading state variable and make use of CircularProgressIndicator(), of course this is a simple solution without using any third party libraries.

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () {},
      child: Container(
        padding: const EdgeInsets.all(10),
        child: _isLoading
            ? SizedBox(
                height: 25,
                width: 25,
                child: CircularProgressIndicator(),
              )
            : Text('ORDER NOW'),
      ),
    );
  }
Bede answered 19/8, 2021 at 6:15 Comment(0)
W
0
// This will work 100%

import 'dart:ui';

import 'package:flutter/material.dart';
 import 'package:http/http.dart' as http;
 import 'dart:convert';
class ButtonWithLoader extends StatefulWidget {
  const ButtonWithLoader({super.key});

  @override
  State<ButtonWithLoader> createState() => _ButtonWithLoaderState();
}

class _ButtonWithLoaderState extends State<ButtonWithLoader> {
  bool? isLoading;
  var itemCount;
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          width: 100,
          child: ElevatedButton(
          style: ElevatedButton.styleFrom(
              minimumSize: const Size(double.infinity, 40),
              textStyle: const TextStyle(fontSize: 10),
              backgroundColor: Colors.green,
            ),
          onPressed:  () async {
                 
                 setState(() {
                   isLoading = true;
                 });
             
               var url =
            Uri.https('www.googleapis.com', '/books/v1/volumes', {'q': '{http}'});
        
          // Await the http get response, then decode the json-formatted response.
          var response = await http.get(url);
          if (response.statusCode == 200) {
          var jsonResponse =
              json.decode(response.body) as Map<String, dynamic>;
           setState(() {
             itemCount = jsonResponse['totalItems'].toString();
           });
          }
                  setState(() {
                   isLoading = false;
                 });
                
              }, child: isLoading == true ? Container(
                                              width: 24,
                                              height: 24,
                                              padding: const EdgeInsets.all(2.0),
                                              child: const CircularProgressIndicator(
                                                color: Colors.white,
                                                strokeWidth: 3,
                                              ),
                                            ) : const Text('Submit')
         ),
        ),
        const SizedBox(height: 50,),
        Text(itemCount ?? '',style: TextStyle(fontWeight: FontWeight.bold),),
      ],
    );
  }
}
Wight answered 27/2, 2023 at 17:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.