AlertDialog
先來看一下AlertDialog的構(gòu)造方法
AlertDialog({
Key key,
///標(biāo)題
this.title,
///標(biāo)題padding
this.titlePadding,
///標(biāo)題style
this.titleTextStyle,
///內(nèi)容
this.content,
///padding
this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),
///style
this.contentTextStyle,
/// 動作 widget 列表,
this.actions,
this.actionsPadding = EdgeInsets.zero,
///action 溢出 方向
this.actionsOverflowDirection,
/// action 溢出水平間距離
this.actionsOverflowButtonSpacing,
///按鈕padding
this.buttonPadding,
///背景色
this.backgroundColor,
///陰影
this.elevation,
this.semanticLabel,
this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none,
this.shape,
///不可滾動,想要滾動需要嵌套SingleChildScrollView
this.scrollable = false,
})
再來看一下創(chuàng)建dialog的方法
Future<T> showDialog<T>({
@required BuildContext context,
WidgetBuilder builder,
///點擊外部是否消失
bool barrierDismissible = true,
///外部陰影顏色
Color barrierColor,
///是否使用安全區(qū)域
bool useSafeArea = true,
bool useRootNavigator = true,
RouteSettings routeSettings,
@Deprecated(
'Instead of using the "child" argument, return the child from a closure '
'provided to the "builder" argument. This will ensure that the BuildContext '
'is appropriate for widgets built in the dialog. '
'This feature was deprecated after v0.2.3.'
)
Widget child,
})
例子
Future<int> _getAlertDialog(BuildContext context) {
return showDialog<int>(
context: context,
builder: (context) => AlertDialog(
title: Text('Title'),
///如果內(nèi)容過長,需要使用SingleChildScrollView
content: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Text(
"這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容..." *
20),
),
),
actions: [
FlatButton(
child: Text('取消'),
onPressed: () => Navigator.of(context).pop(0),
),
FlatButton(
child: Text('確定'),
onPressed: () => Navigator.of(context).pop(1),
)
],
),
///點擊dialog 外部是否消失
barrierDismissible: true);
}
Future<T> showDialog<T>
showDialog<T>()是Material組件庫提供的一個用于彈出Material風(fēng)格對話框的方法,并返回int類型,取消的時候返回0,確定的時候返回1,比較簡單,
這里唯一需要注意的是關(guān)閉dialog 方法, Navigator.of(context).pop({Object result}),這個和路由管理關(guān)閉頁面的方式是一樣的
Future<T> showDialog<T>({
@required BuildContext context,
WidgetBuilder builder,
bool barrierDismissible = true,
Color barrierColor,
bool useSafeArea = true,
bool useRootNavigator = true,
RouteSettings routeSettings,
@Deprecated(
'Instead of using the "child" argument, return the child from a closure '
'provided to the "builder" argument. This will ensure that the BuildContext '
'is appropriate for widgets built in the dialog. '
'This feature was deprecated after v0.2.3.'
)
Widget child,
}) {
assert(child == null || builder == null);
assert(barrierDismissible != null);
assert(useSafeArea != null);
assert(useRootNavigator != null);
assert(debugCheckHasMaterialLocalizations(context));
final ThemeData theme = Theme.of(context, shadowThemeOnly: true);
return showGeneralDialog(
context: context,
pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) {
final Widget pageChild = child ?? Builder(builder: builder);
Widget dialog = Builder(
builder: (BuildContext context) {
return theme != null
? Theme(data: theme, child: pageChild)
: pageChild;
}
);
if (useSafeArea) {
dialog = SafeArea(child: dialog);
}
return dialog;
},
barrierDismissible: barrierDismissible,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierColor: barrierColor ?? Colors.black54,
transitionDuration: const Duration(milliseconds: 150),
transitionBuilder: _buildMaterialDialogTransitions,
useRootNavigator: useRootNavigator,
routeSettings: routeSettings,
);
}
看了一下showDialog 的源碼,是對showGeneralDialog這個方法進(jìn)行了包裝,發(fā)現(xiàn)了如果使用了MaterialAppTheme 則該dialog使用 MaterialAppTheme , 其他的都是固定封裝,
Future<T> showGeneralDialog<T>
Future<T> showGeneralDialog<T>({
@required BuildContext context,
@required RoutePageBuilder pageBuilder,
bool barrierDismissible,
String barrierLabel,
Color barrierColor,
Duration transitionDuration,
RouteTransitionsBuilder transitionBuilder,
bool useRootNavigator = true,
RouteSettings routeSettings,
}) {
assert(pageBuilder != null);
assert(useRootNavigator != null);
assert(!barrierDismissible || barrierLabel != null);
return Navigator.of(context, rootNavigator: useRootNavigator).push<T>(_DialogRoute<T>(
pageBuilder: pageBuilder,
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
barrierColor: barrierColor,
transitionDuration: transitionDuration,
transitionBuilder: transitionBuilder,
settings: routeSettings,
));
}
而 showGeneralDialog 則是使用 Navigator.push了一個 _DialogRoute ,這里也就解釋了關(guān)閉dialog 為什么是
Navigator.pop的方法了,
這個例子我為了演示嵌套滑動的效果,我使用SingleChildScrollView
但是我覺得現(xiàn)在大部分dialog的設(shè)計應(yīng)該是這樣的
這種方式如果使用actions 和content 來寫的話,想到什么辦法,只能利用content 來寫所有的布局
這是我利用content寫出來的結(jié)果,
Future<int> _getAlertDialog(BuildContext context) {
return showDialog<int>(
context: context,
builder: (context) => AlertDialog(
// title: Container(
// alignment: Alignment.center,
// child: Text('Title'),
// ),
/// 修改內(nèi)容邊距
contentPadding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
/// 修改圓角大小
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
///如果內(nèi)容過長,需要使用 SingleChildScrollView
content: SizedBox(
height: 180,
child: Column(
children: [
SizedBox(
height: 120,
///包裹內(nèi)容,為了使滑動開始位置是從距離30的位置開始
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 10),
child: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Text(
"這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容...這個是內(nèi)容..." *
20),
),
),
)
),
/// 水平橫線
Divider(
height: 10,
),
/// 為了均分按鈕 ,
Row(
children: [
Expanded(
flex: 1,
child: FlatButton(
child: Text(
'取消',
style:
TextStyle(color: Colors.black87, fontSize: 18),
),
onPressed: () => Navigator.of(context).pop(0),
),
),
SizedBox(
height: 30,
child:VerticalDivider(
width:10,
),
),
Expanded(
flex: 1,
child: FlatButton(
child: Text(
'確定',
style: TextStyle(
color: Colors.blueAccent, fontSize: 18),
),
onPressed: () => Navigator.of(context).pop(1),
),
)
],
),
],
),
),
),
///點擊dialog 外部是否消失
barrierDismissible: true);
}
其實這中類似ios樣式的控件Flutter在設(shè)計之初也想到了,在Cupertino 組件中就有CupertinoDialog ,不過到了現(xiàn)在版本已經(jīng)被放棄了,使用CupertinoAlertDialog替代了CupertinoDialog 使用方式和dialog是一致的,說實話android機(jī)器上顯示的這個dialog 確實和ios的效果沒啥差別,官方合適很良心的
例子
getCupertinoAlertDialog(BuildContext context) {
return showDialog<int>(context: context,builder: (con){
return CupertinoAlertDialog(
title: Text("This is Title"),
content: Text('This is content'*10),
actions: [
FlatButton(
onPressed: (){
Navigator.of(context).pop(0);
},
child: Text('取消'),
),
FlatButton(
onPressed: (){
Navigator.of(context).pop(0);
},
child: Text('中間的'),
),
FlatButton(
onPressed: (){
Navigator.of(context).pop(1);
},
child: Text('確定'),
),
],
);
});
}
效果圖
SimpleDialog
再開看一下他的構(gòu)造方法
SimpleDialog({
Key key,
this.title,
this.titlePadding = const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
this.titleTextStyle,
this.children,
this.contentPadding = const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0),
this.backgroundColor,
this.elevation,
this.semanticLabel,
this.shape,
})
例子
_getSimpleDialog(BuildContext context) async {
var lan = await showDialog<int>(
context: context,
builder: (context) => SimpleDialog(
title: Text('Title'),
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SimpleDialogOption(
child: Text('這個是第一個'),
onPressed: () => Navigator.of(context).pop(0),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SimpleDialogOption(
child: Text('這個是第二個'),
onPressed: () => Navigator.of(context).pop(1),
),
)
],
),
);
printString('language is ${lan}');
}
效果圖
這里的子條目使用的是SimpleDialogOption ,他相當(dāng)如一個button
showModalBottomSheet
在介紹Scaffold 的時候介紹過showModalBottomSheet 創(chuàng)建一個類似bottomsheetdialog,
這里寫一個日期選擇
先來樣式
void selectDate(BuildContext context) async {
DateTime dateTime = DateTime.now();
var date = await showModalBottomSheet<DateTime>(
context: context,
builder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Padding(
padding: const EdgeInsets.all(19),
child: Text('取消'),
),
)),
Expanded(
flex: 1,
child: GestureDetector(
onTap: () {
Navigator.of(context).pop(dateTime);
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('確定', textDirection: TextDirection.rtl),
),
)),
],
),
SizedBox(
height: 200,
child: CupertinoDatePicker(
onDateTimeChanged: (date) {
dateTime = date;
},
mode: CupertinoDatePickerMode.date,
maximumDate: DateTime.now().add(Duration(days: 20)),
minimumDate: DateTime.now().add(Duration(days: -20)),
),
)
],
),
);
printString('date:${date ?? ''}');
}
我學(xué)習(xí)flutter的整個過程都記錄在里面了
http://www.reibang.com/c/36554cb4c804
最后附上demo 地址