在耗時(shí)操作的時(shí)候硕蛹,一般都要彈出一個(gè)加載框浪漠,然后在完成的時(shí)候再把加載框關(guān)掉秕豫,在Flutter中可以直接用showDialog()來(lái)彈出一個(gè)對(duì)話框驳阎。
showDialog(
context: context,
builder: (ctx) {
return SimpleDialog(
title: Text(""),
titlePadding: EdgeInsets.all(10),
backgroundColor: Colors.white,
elevation: 5,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(6))),
children: <Widget>[
ListTile(
title: Center(
child: Text(
"請(qǐng)?zhí)顚懲暾畔ⅲ?,
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
),
SizedBox(height: 15),
ListTile(
title: Center(
child: Container(
padding: EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 8),
width: 100,
alignment: Alignment.center,
decoration: BoxDecoration(color: MyColors.primaryColor),
child: Text(
"知道了",
style: TextStyle(color: Colors.white, fontSize: 18),
),
)),
onTap: () {
Navigator.pop(context);
},
),
],
);
});
這是一個(gè)簡(jiǎn)單的提示對(duì)話框,包含了關(guān)閉按鈕馁蒂,點(diǎn)擊就能關(guān)閉呵晚。但一般的耗時(shí)操作完成,就需要我們自己把dialog關(guān)閉掉沫屡。
首先饵隙,開(kāi)啟dialog的時(shí)機(jī)。由于我們需要獲取到BuildContext沮脖,所以就得等build()方法走完金矛,這里可以用Future.delayed()來(lái)等創(chuàng)建好BuildContext再進(jìn)行創(chuàng)建,或者用Timer來(lái)延遲操作勺届,我選擇了前者驶俊。
Future.delayed(Duration.zero, () {
_showDialog();
});
void _showDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return LoadingDialog(true);
});
}
其中delayed()在initState()結(jié)尾來(lái)做就行,這里參考網(wǎng)友封裝了一個(gè)LoadingDialog免姿。
class LoadingDialog extends Dialog {
LoadingDialog(this.canceledOnTouchOutside) : super();
///點(diǎn)擊背景是否能夠退出
final bool canceledOnTouchOutside;
@override
Widget build(BuildContext context) {
return Center(
child: new Material(
///背景透明
color: Colors.transparent,
///保證控件居中效果
child: Stack(
children: <Widget>[
GestureDetector(
///點(diǎn)擊事件
onTap: () {
if (canceledOnTouchOutside) {
Navigator.pop(context);
}
},
),
_dialog()
],
)),
);
}
Widget _dialog() {
return new Center(
///彈框大小
child: new SizedBox(
width: 120.0,
height: 120.0,
child: new Container(
///彈框背景和圓角
decoration: ShapeDecoration(
color: Color(0xffffffff),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new CircularProgressIndicator(),
new Padding(
padding: const EdgeInsets.only(
top: 20.0,
),
child: new Text(
"加載中",
style: new TextStyle(fontSize: 16.0),
),
),
],
),
),
),
);
}
}
那么接下來(lái)要在什么時(shí)機(jī)關(guān)閉呢饼酿?
一開(kāi)始,我理所當(dāng)然的以為,是在異步方法結(jié)束后故俐,去更新界面的時(shí)候關(guān)閉想鹰,也就是setState(() {})的時(shí)候,可是不管怎么嘗試药版,用Navigator.pop()不行辑舷,用Navigator.of(context, rootNavigator: true).pop(result)也不行,用FlutterBoost.singleton.close(id)也不行槽片,用FlutterBoost.singleton.closeCurrent()也不行何缓,都會(huì)直接把非Dialog的頁(yè)面也關(guān)閉掉,這讓我百思不得其解还栓,因?yàn)閟howDialog()的本質(zhì)也是新建了一個(gè)Route出來(lái)歌殃,也就是最頂層的頁(yè)面是彈出的Dialog,可是為什么關(guān)不掉呢蝙云。
一番思前想后氓皱,把showDialog的邏輯移到和異步邏輯同級(jí),也就是setState(() {})外面勃刨,然后把showDialog()自身創(chuàng)建的BuildContext傳進(jìn)去就能正常關(guān)閉了波材。也就是,在setState(() {})的時(shí)候身隐,其實(shí)用的context還是非Dialog頁(yè)面的廷区,所以關(guān)閉的當(dāng)然就不是Dialog了。
BuildContext dialogContext;
void _showDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
dialogContext = context;
return LoadingDialog(true);
});
}
持有Dialog自己的BuildContext贾铝,然后在異步以后調(diào)用就行了隙轻。
Future _getMsg() async {
try {
var restHomeId = await DataManager.getInstance().getLocalRestHomeId();
CurrentStaffModel cs = await DataManager.getInstance().getCurrentStaffInfo();
Map<String, dynamic> params = Map();
params["staffId"] = cs.staffId;
params["restHomeId"] = restHomeId;
var result = await CourseManager.getInstance().getStudentCourseList(params);
setState(() {});
Navigator.pop(dialogContext); //直接傳入context關(guān)閉就行
} catch (e) {
LogUtil.e(e.toString());
}
}