Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show a progress Dialog before data loading in flutter?

In my Flutter project, I am doing API calls to fetch data by GET request. After parsing the JSON object from the response, I just show the value in the Text widget. While the data takes time to load, in the meantime my Text widgets show null.

For the API calling section I have the following code-

class Webservice {
  Future<T> load<T>(Resource<T> resource) async {
    var jwt = await LocalStore().getJWT();
    print(jwt);

    final response = await http.get(resource.url,
        headers: {
          'Content-Type': 'application/json',
          'token': '${Constants.TOKEN}',
          'jwt': '$jwt',
        }
    );
    if(response.statusCode == 200) {
      print('${response.body}');
      return resource.parse(response);
    } else {
      throw Exception('Failed to load data!');
    }
  }
}

I made a Model class for JSON parsing-

class Category {
  int catNote;
  int catTodo;
  int catRem;
  int catTag;
  int catUrgent;
  int catWork;
  int catOffice;
  int catPersonal;
  
  Category(
      {this.catNote,
        this.catTodo,
        this.catRem,
        this.catTag,
        this.catUrgent,
        this.catWork,
        this.catOffice,
        this.catPersonal});

  Category.fromJson(Map<String, dynamic> json) {
    catNote = json['cat_note'];
    catTodo = json['cat_todo'];
    catRem = json['cat_rem'];
    catTag = json['cat_tag'];
    catUrgent = json['cat_urgent'];
    catWork = json['cat_work'];
    catOffice = json['cat_office'];
    catPersonal = json['cat_personal'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['cat_note'] = this.catNote;
    data['cat_todo'] = this.catTodo;
    data['cat_rem'] = this.catRem;
    data['cat_tag'] = this.catTag;
    data['cat_urgent'] = this.catUrgent;
    data['cat_work'] = this.catWork;
    data['cat_office'] = this.catOffice;
    data['cat_personal'] = this.catPersonal;
    return data;
  }

  static Resource<Category> get allCategory {
    return Resource(
        url: '${Constants.BASE_URL}category',
        parse: (response) {
          print('my result ${response.body}');
          final result = json.decode(response.body);

          Category category = Category.fromJson(result) ;
          return category;

        }
    );

  }

}

Now, in my main class, I have created one function like below-

  void _getAllCategories() {
    Webservice().load(Category.allCategory).then((newsArticles) => {
        setState(() => {
      _category = newsArticles
    })
  });
 }

After that, I have called the function inside the initState function and saved the value in the _category object.

Then inside the Widget build(BuildContext context) function for Text widget I have used the value from _category object like below using a ternary operator to check whether the object is null or not. If it's null then it should show 0 and if it is not null then should show the original value-

child: _category ==null?
                Text('0',
                style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold
                ),
                ):
                Text('${_category.catToDo}',
                  style: TextStyle(
                      fontSize: 30,
                      fontWeight: FontWeight.bold
                  ),
                )

But it is still showing null whiling taking few second for data loading and shows output like below-

enter image description here

So, I need a solution to show a progress dialog or just show the default value as 0 while the data takes time to load. It would be very nice if someone helps me out with this code.

like image 208
S. M. Asif Avatar asked Jul 23 '19 14:07

S. M. Asif


4 Answers

You can check this package to show a loading spin with different styles.

After that you need to use Future Builder widget

Here is an example of how to use it with the spinkit

FutureBuilder(
        future: myAwesomeFutureMethod(), // you should put here your method that call your web service
        builder:

            (BuildContext context, AsyncSnapshot<List<BillResponse>> snapshot) { 
            /// The snapshot data type have to be same of the result of your web service method
          if (snapshot.hasData) {
            /// When the result of the future call respond and has data show that data
            return SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: bodyData(snapshot.data),
            );
          }
          /// While is no data show this
          return Center(
            child: SpinKitDualRing(
              color: Colors.blue,
            ),
          );
        },
      ),

Hope this could help. Cheers.

like image 187
Enzo Lizama Avatar answered Oct 19 '22 11:10

Enzo Lizama


Use a FutureBuilder to control the rendering during the load time;

  final categories = Webservice().load(Category.allCategory);

  Widget build(BuildContext context) {
    return FutureBuilder(
      future: categories,
      builder: (ctx, snapshot) {
        var value = (snapshot.connectionState == ConnectionState.done) ? '${_category.catToDo}' : '0';

        return Text(
          value,
          style: TextStyle(
            fontSize: 30,
            fontWeight: FontWeight.bold
          ),
        );
      }
    );
  }

Or if you want to display a loading animation :

  final categories = Webservice().load(Category.allCategory);

  Widget build(BuildContext context) {
    return FutureBuilder(
      future: categories,
      builder: (ctx, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Text(
            '${_category.catToDo}',
            style: TextStyle(
              fontSize: 30,
              fontWeight: FontWeight.bold
            ),
          );
        }
        else {
          return CircularProgressIndicator();
        }
      }
    );
  }
like image 43
Muldec Avatar answered Oct 19 '22 12:10

Muldec


Make sure that _category is null, maybe you're assigning a value to it before loading the data.

like image 39
Abdou Ouahib Avatar answered Oct 19 '22 11:10

Abdou Ouahib


If you want to show the Cellular bar progress indicator, the following is the demo for it:

enter image description here

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyWidget(),
    ),
  );
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            BarProgressIndicator(
              numberOfBars: 4,
              color: Colors.white,
              fontSize: 5.0,
              barSpacing: 2.0,
              beginTweenValue: 5.0,
              endTweenValue: 13.0,
              milliseconds: 200,
            ),
            Text(
              'Cellular bar progress indicator',
              style: TextStyle(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

class BarProgressIndicator extends StatefulWidget {
  final int numberOfBars;
  final double fontSize;
  final double barSpacing;
  final Color color;
  final int milliseconds;
  final double beginTweenValue;
  final double endTweenValue;

  BarProgressIndicator({
    this.numberOfBars = 3,
    this.fontSize = 10.0,
    this.color = Colors.black,
    this.barSpacing = 0.0,
    this.milliseconds = 250,
    this.beginTweenValue = 5.0,
    this.endTweenValue = 10.0,
  });

  _BarProgressIndicatorState createState() => _BarProgressIndicatorState(
        numberOfBars: this.numberOfBars,
        fontSize: this.fontSize,
        color: this.color,
        barSpacing: this.barSpacing,
        milliseconds: this.milliseconds,
        beginTweenValue: this.beginTweenValue,
        endTweenValue: this.endTweenValue,
      );
}

class _BarProgressIndicatorState extends State<BarProgressIndicator>
    with TickerProviderStateMixin {
  int numberOfBars;
  int milliseconds;
  double fontSize;
  double barSpacing;
  Color color;
  double beginTweenValue;
  double endTweenValue;
  List<AnimationController> controllers = new List<AnimationController>();
  List<Animation<double>> animations = new List<Animation<double>>();
  List<Widget> _widgets = new List<Widget>();

  _BarProgressIndicatorState({
    this.numberOfBars,
    this.fontSize,
    this.color,
    this.barSpacing,
    this.milliseconds,
    this.beginTweenValue,
    this.endTweenValue,
  });

  initState() {
    super.initState();
    for (int i = 0; i < numberOfBars; i++) {
      _addAnimationControllers();
      _buildAnimations(i);
      _addListOfDots(i);
    }

    controllers[0].forward();
  }

  void _addAnimationControllers() {
    controllers.add(AnimationController(
        duration: Duration(milliseconds: milliseconds), vsync: this));
  }

  void _addListOfDots(int index) {
    _widgets.add(Padding(
      padding: EdgeInsets.only(right: barSpacing),
      child: _AnimatingBar(
        animation: animations[index],
        fontSize: fontSize,
        color: color,
      ),
    ));
  }

  void _buildAnimations(int index) {
    animations.add(
        Tween(begin: widget.beginTweenValue, end: widget.endTweenValue)
            .animate(controllers[index])
              ..addStatusListener((AnimationStatus status) {
                if (status == AnimationStatus.completed)
                  controllers[index].reverse();
                if (index == numberOfBars - 1 &&
                    status == AnimationStatus.dismissed) {
                  controllers[0].forward();
                }
                if (animations[index].value > widget.endTweenValue / 2 &&
                    index < numberOfBars - 1) {
                  controllers[index + 1].forward();
                }
              }));
  }

  Widget build(BuildContext context) {
    return SizedBox(
      height: 30.0,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.center,
        children: _widgets,
      ),
    );
  }

  dispose() {
    for (int i = 0; i < numberOfBars; i++) controllers[i].dispose();
    super.dispose();
  }
}

class _AnimatingBar extends AnimatedWidget {
  final Color color;
  final double fontSize;
  _AnimatingBar(
      {Key key, Animation<double> animation, this.color, this.fontSize})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return Container(
      height: animation.value,
      decoration: BoxDecoration(
        shape: BoxShape.rectangle,
        border: Border.all(color: color),
        borderRadius: BorderRadius.circular(2.0),
        color: color,
      ),
      width: fontSize,
    );
  }
}
like image 39
Javeed Ishaq Avatar answered Oct 19 '22 11:10

Javeed Ishaq