Dialog 在我们的日常开发中是必不可少的,Flutter 也提供了 AlertDialog / SimpleDialog 供我们选择,但是对于开发还是不足够的,小菜尝试了一下自定义对话框,简单记录一下。
1. 继承 Dialog
Dialog 只是一个基础的 Widget 不会直接使用,小菜想自定义 Dialog 必须先继承 Dialog。此时需要重写 Widget build(BuildContext context) 方法。
2. 绘制 Dialog 样式
小菜尝试做一个性别选择框,包括标题,图片和按钮等。
import 'package:flutter/material.dart';
class GenderChooseDialog extends Dialog {
GenderChooseDialog({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Padding(
padding: const EdgeInsets.all(12.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.fromLTRB(
10.0, 40.0, 10.0, 28.0),
child: Center(
child: new Text('请选择性别',
style: new TextStyle(
fontSize: 20.0,
)))),
new Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_genderChooseItemWid(1),
_genderChooseItemWid(2)
])
]))
])));
}
Widget _genderChooseItemWid(var gender) {
return GestureDetector(
child: Column(children: <Widget>[
Image.asset(
gender == 1
? 'images/icon_type_boy.png'
: 'images/icon_type_girl.png',
width: 135.0,
height: 135.0),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 22.0, 0.0, 40.0),
child: Text(gender == 1 ? '我是男生' : '我是女生',
style: TextStyle(
color: Color(gender == 1 ? 0xff4285f4 : 0xffff4444),
fontSize: 15.0)))
]));
}
}
3. 内容传参
小菜尽量把对话框做到通用性强一些,小菜测试仅把标题当参数传递,一个参数与多个参数是类似的。
class GenderChooseDialog extends Dialog {
var title;
GenderChooseDialog({
Key key,
@required this.title,
}) : super(key: key);
@override
Widget build(BuildContext context) { }
}
4. 添加点击事件
每个对话框要有自己的点击事件,小菜准备把点击不同图片或文字时添加不同的点击事件。需要自定义 Function 方法。
class GenderChooseDialog extends Dialog {
var title;
Function onBoyChooseEvent;
Function onGirlChooseEvent;
GenderChooseDialog({
Key key,
@required this.title,
@required this.onBoyChooseEvent,
@required this.onGirlChooseEvent,
}) : super(key: key);
Widget _genderChooseItemWid(var gender) {
return GestureDetector(
onTap: gender == 1 ? this.onBoyChooseEvent : this.onGirlChooseEvent,
child: Column(children: <Widget>[
Image.asset(
gender == 1 ? 'images/icon_type_boy.png'
: 'images/icon_type_girl.png',
width: 135.0, height: 135.0),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 22.0, 0.0, 40.0),
child: Text(gender == 1 ? '我是男生' : '我是女生',
style: TextStyle(
color: Color(gender == 1 ? 0xff4285f4 : 0xffff4444),
fontSize: 15.0)))
]));
}
}
// 方法调用
void _onItemPressed() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return GenderChooseDialog(
title: '小哥哥小姐姐请选择',
onBoyChooseEvent: () {
Navigator.pop(context);
},
onGirlChooseEvent: () {
Navigator.pop(context);
});
});
}
5. 注意事项
- Dialog 也是 Widget 默认是占满全屏,所以小菜自己绘制部分对话框,为了协调,借助 type: MaterialType.transparency 设置了对话框外半透明效果;
- 无论是传参还是设置点击事件,都需要在初始化中添加,很像 Android 中对 RecycleView 设置内容和点击事件等;
GenderChooseDialog({
Key key,
@required this.title,
@required this.onBoyChooseEvent,
@required this.onGirlChooseEvent,
}) : super(key: key);
- 在 showDialog 方法中,barrierDismissible: false 属性代表点击顶部状态栏(显示电量/时间的横条位置)时是否关闭对话框,如果想点击半透明位置时关闭对话框,可以再添加一个点击事件即可。
小菜目前的学习还仅限于基本的使用,如果有不对的地方还希望多多指出。
来源:阿策小和尚