如何在颤振中加载数据之前显示进度对话框?
How to show a progress Dialog before data loading in flutter?
在我的 Flutter 项目中,我正在执行 API 调用以通过 GET 请求获取数据。从响应中解析 JSON 对象 后,我只在 Text 小部件中显示该值。虽然加载数据需要时间,但同时我的文本小部件显示为空。
对于 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!');
}
}
}
我做了一个模型class用于JSON解析-
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;
}
);
}
}
现在,在我的主 class 中,我创建了一个如下所示的函数 -
void _getAllCategories() {
Webservice().load(Category.allCategory).then((newsArticles) => {
setState(() => {
_category = newsArticles
})
});
}
之后,我调用了 initState 函数内部的函数,并将值保存在 _category 对象中。
然后在文本小部件的 Widget build(BuildContext context) 函数中,我使用了 _category 对象中的值,如下所示,使用三元运算符检查对象是否为空。如果它为 null 那么它应该显示 0 如果它不为 null 那么它应该显示原始值 -
child: _category ==null?
Text('0',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
),
):
Text('${_category.catToDo}',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
),
)
但是它仍然显示空值,同时需要几秒钟的时间来加载数据并显示如下输出-
因此,我需要一个解决方案来显示进度对话框或仅将默认值显示为 0,而数据加载需要时间。如果有人能帮我解决这段代码,那就太好了。
在加载期间使用 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();
}
}
);
}
您可以检查 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,
),
);
},
),
希望这对您有所帮助。干杯。
确保 _category
为 null,也许您在加载数据之前为其赋值。
您应该使用 FutureBuilder
class 来执行此操作。
此示例展示了一个 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,
),
);
},
),
);
}
}
如果你想显示Cellular bar progress indicator,下面是它的演示:
导入'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,
);
}
}
不使用 Futurebuilder
在API来电之前,点赞
AlertDialog alert = AlertDialog(
content: Row(children: [
CircularProgressIndicator(
backgroundColor: Colors.red,
),
Container(margin: EdgeInsets.only(left: 7), child: Text("Loading...")),
]),
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
},
);
getAllCategories() //API call
收到 API 回复后
var response = getAllCategories() //API call
Navigator.pop(context);
注意:您可以将代码放入方法中,然后在此处调用
在我的 Flutter 项目中,我正在执行 API 调用以通过 GET 请求获取数据。从响应中解析 JSON 对象 后,我只在 Text 小部件中显示该值。虽然加载数据需要时间,但同时我的文本小部件显示为空。
对于 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!');
}
}
}
我做了一个模型class用于JSON解析-
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;
}
);
}
}
现在,在我的主 class 中,我创建了一个如下所示的函数 -
void _getAllCategories() {
Webservice().load(Category.allCategory).then((newsArticles) => {
setState(() => {
_category = newsArticles
})
});
}
之后,我调用了 initState 函数内部的函数,并将值保存在 _category 对象中。
然后在文本小部件的 Widget build(BuildContext context) 函数中,我使用了 _category 对象中的值,如下所示,使用三元运算符检查对象是否为空。如果它为 null 那么它应该显示 0 如果它不为 null 那么它应该显示原始值 -
child: _category ==null?
Text('0',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
),
):
Text('${_category.catToDo}',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold
),
)
但是它仍然显示空值,同时需要几秒钟的时间来加载数据并显示如下输出-
因此,我需要一个解决方案来显示进度对话框或仅将默认值显示为 0,而数据加载需要时间。如果有人能帮我解决这段代码,那就太好了。
在加载期间使用 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();
}
}
);
}
您可以检查 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,
),
);
},
),
希望这对您有所帮助。干杯。
确保 _category
为 null,也许您在加载数据之前为其赋值。
您应该使用 FutureBuilder
class 来执行此操作。
此示例展示了一个 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,
),
);
},
),
);
}
}
如果你想显示Cellular bar progress indicator,下面是它的演示:
导入'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,
);
}
}
不使用 Futurebuilder
在API来电之前,点赞
AlertDialog alert = AlertDialog(
content: Row(children: [
CircularProgressIndicator(
backgroundColor: Colors.red,
),
Container(margin: EdgeInsets.only(left: 7), child: Text("Loading...")),
]),
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
},
);
getAllCategories() //API call
收到 API 回复后
var response = getAllCategories() //API call
Navigator.pop(context);
注意:您可以将代码放入方法中,然后在此处调用