【问题标题】:How to show a progress Dialog before data loading in flutter?如何在颤动中加载数据之前显示进度对话框?
【发布时间】:2019-12-01 15:38:30
【问题描述】:

在我的 Flutter 项目中,我正在执行 API 调用以通过 GET 请求获取数据。从响应中解析出 JSON 对象 后,我只在 Text 小部件中显示该值。虽然加载数据需要时间,但与此同时,我的 Text 小部件显示为 null。

对于 API 调用部分,我有以下代码-

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!');
    }
  }
}

我为 JSON 解析做了一个 Model 类-

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;

        }
    );

  }

}

现在,在我的主课中,我创建了一个如下所示的函数-

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

之后,我在 initState 函数中调用了该函数,并将值保存在 _category 对象中。

然后在文本小部件的 Widget build(BuildContext context) 函数中,我使用了来自 _category 对象的值,如下所示,使用三元运算符来检查对象是否是是否为空。如果为空,则应显示 0,如果不为空,则应显示原始值-

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

但它仍然显示空值,而数据加载需要几秒钟,并显示如下输出-

所以,我需要一个解决方案来显示进度对话框,或者在数据加载需要时间时将默认值显示为 0。如果有人帮助我编写这段代码,那就太好了。

【问题讨论】:

标签: flutter dart progress-bar loading dataloader


【解决方案1】:

在加载期间使用 FutureBuilder 控制渲染;

  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
          ),
        );
      }
    );
  }

或者如果你想显示加载动画:

  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();
        }
      }
    );
  }

【讨论】:

    【解决方案2】:

    您可以检查this 包以显示具有不同样式的加载旋转。

    之后你需要使用Future Builder小部件

    这是一个如何与 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,
                ),
              );
            },
          ),
    

    希望这会有所帮助。干杯。

    【讨论】:

      【解决方案3】:

      您应该使用FutureBuilder 类来执行此操作。

      此示例显示了一个FutureBuilder,它在加载数据时显示加载微调器。如果 Future 以结果完成,则显示成功图标和文本,如果 Future 以错误完成,则显示错误图标和文本。假设 _calculation 字段是通过按下 UI 中其他位置的按钮来设置的。

      这是一个例子

      class MyStatefulWidget extends StatefulWidget {
        MyStatefulWidget({Key key}) : super(key: key);
      
        @override
        _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
      }
      
      /// This is the private State class that goes with MyStatefulWidget.
      class _MyStatefulWidgetState extends State<MyStatefulWidget> {
        Future<String> _calculation = Future<String>.delayed(
          Duration(seconds: 2),
          () => 'Data Loaded',
        );
      
        Widget build(BuildContext context) {
          return DefaultTextStyle(
            style: Theme.of(context).textTheme.headline2,
            textAlign: TextAlign.center,
            child: FutureBuilder<String>(
              future: _calculation, // a previously-obtained Future<String> or null
              builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
                List<Widget> children;
                if (snapshot.hasData) {
                  children = <Widget>[
                    Icon(
                      Icons.check_circle_outline,
                      color: Colors.green,
                      size: 60,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 16),
                      child: Text('Result: ${snapshot.data}'),
                    )
                  ];
                } else if (snapshot.hasError) {
                  children = <Widget>[
                    Icon(
                      Icons.error_outline,
                      color: Colors.red,
                      size: 60,
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 16),
                      child: Text('Error: ${snapshot.error}'),
                    )
                  ];
                } else {
                  children = <Widget>[
                    SizedBox(
                      child: CircularProgressIndicator(),
                      width: 60,
                      height: 60,
                    ),
                    const Padding(
                      padding: EdgeInsets.only(top: 16),
                      child: Text('Awaiting result...'),
                    )
                  ];
                }
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: children,
                  ),
                );
              },
            ),
          );
        }
      }
      

      【讨论】:

        【解决方案4】:

        确保_category 为空,也许您在加载数据之前为其分配了一个值。

        【讨论】:

          【解决方案5】:

          如果你想显示 Cellular bar 进度指示器,下面是它的演示:

          导入'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,
              );
            }
          }
          

          【讨论】:

          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          猜你喜欢
          • 2020-06-13
          • 2022-01-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-22
          • 1970-01-01
          • 2011-07-09
          • 1970-01-01
          相关资源
          最近更新 更多