Flutter - 自定義Dialog
開(kāi)發(fā)中,我們經(jīng)常需要向用戶展示信息,多數(shù)情況下,我們使用dialog展示提示信息,那么在Flutter中如何創(chuàng)建dialog, 并使用呢?現(xiàn)在就讓我們來(lái)看看如何打造我們自己的dialog對(duì)象。
Dialog對(duì)象,我們需要重寫build函數(shù)
自定義Dialog對(duì)象,需要繼承Dialog類,盡管Dialog提供了child參數(shù)供寫視圖界面,但是往往會(huì)達(dá)不到我們想要的效果,因?yàn)槟J(rèn)的Dialog背景框是滿屏的。。。那么我們就需要完全定義界面了,就需要重寫build函數(shù)。下面我們編寫一個(gè)加載對(duì)話框,如圖示:
如圖,我們需要打造一個(gè)類似的對(duì)話框,應(yīng)該具體實(shí)現(xiàn)呢?首先,繼承Dialog
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class LoadingDialog extends Dialog {
String text;
LoadingDialog({Key key, @required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Material( //創(chuàng)建透明層
type: MaterialType.transparency, //透明類型
child: 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(
text,
style: new TextStyle(fontSize: 12.0),
),
),
],
),
),
),
),
);
}
}
上面我們已經(jīng)創(chuàng)建了一個(gè)加載對(duì)話框,那么我們?cè)撊绾握故具@個(gè)dialog呢?showDialog函數(shù)
showDialog<Null>(
context: context, //BuildContext對(duì)象
barrierDismissible: false,
builder: (BuildContext context) {
return new LoadingDialog( //調(diào)用對(duì)話框
text: '正在獲取詳情...',
);
});
對(duì)話框展示后,我們還需要關(guān)閉呀。關(guān)閉其實(shí)就很簡(jiǎn)單了!
Navigator.pop(context); //關(guān)閉對(duì)話框
再來(lái)個(gè)栗子,看客請(qǐng)注意
// ignore: must_be_immutable
class MessageDialog extends Dialog {
String title;
String message;
String negativeText;
String positiveText;
Function onCloseEvent;
Function onPositivePressEvent;
MessageDialog({
Key key,
@required this.title,
@required this.message,
this.negativeText,
this.positiveText,
this.onPositivePressEvent,
@required this.onCloseEvent,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Padding(
padding: const EdgeInsets.all(15.0),
child: new Material(
type: MaterialType.transparency,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Container(
decoration: ShapeDecoration(
color: Color(0xffffffff),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
margin: const EdgeInsets.all(12.0),
child: new Column(
children: <Widget>[
new Padding(
padding: const EdgeInsets.all(10.0),
child: new Stack(
alignment: AlignmentDirectional.centerEnd,
children: <Widget>[
new Center(
child: new Text(
title,
style: new TextStyle(
fontSize: 19.0,
),
),
),
new GestureDetector(
onTap: this.onCloseEvent,
child: new Padding(
padding: const EdgeInsets.all(5.0),
child: new Icon(
Icons.close,
color: Color(0xffe0e0e0),
),
),
),
],
),
),
new Container(
color: Color(0xffe0e0e0),
height: 1.0,
),
new Container(
constraints: BoxConstraints(minHeight: 180.0),
child: new Padding(
padding: const EdgeInsets.all(12.0),
child: new IntrinsicHeight(
child: new Text(
message,
style: TextStyle(fontSize: 16.0),
),
),
),
),
this._buildBottomButtonGroup(),
],
),
),
],
),
),
);
}
Widget _buildBottomButtonGroup() {
var widgets = <Widget>[];
if (negativeText != null && negativeText.isNotEmpty) widgets.add(_buildBottomCancelButton());
if (positiveText != null && positiveText.isNotEmpty) widgets.add(_buildBottomPositiveButton());
return new Flex(
direction: Axis.horizontal,
children: widgets,
);
}
Widget _buildBottomCancelButton() {
return new Flexible(
fit: FlexFit.tight,
child: new FlatButton(
onPressed: onCloseEvent,
child: new Text(
negativeText,
style: TextStyle(
fontSize: 16.0,
),
),
),
);
}
Widget _buildBottomPositiveButton() {
return new Flexible(
fit: FlexFit.tight,
child: new FlatButton(
onPressed: onPositivePressEvent,
child: new Text(
positiveText,
style: TextStyle(
color: Color(Colors.teal.value),
fontSize: 16.0,
),
),
),
);
}
}
效果圖:
通過(guò)查看評(píng)論,評(píng)論里有朋友說(shuō)對(duì)話框不支持透明區(qū)域的點(diǎn)擊
邏輯:通過(guò) ** Stack ** 疊加一個(gè) ** GestureDetector ** 布局,添加一個(gè)點(diǎn)擊事件即可。這個(gè)方法是一個(gè)網(wǎng)友告訴我的,之前我也很頭疼這個(gè),感謝!
查看源碼:
WillPopScope(
onWillPop: () {
_onNavigationClickEvent();
return Future.value(false);
},
child: Material(
type: MaterialType.transparency,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
GestureDetector(onTap: _onNavigationClickEvent),
_buildContentView(), //構(gòu)建具體的對(duì)話框布局內(nèi)容
],
),
),
)