引言:
实现一个弹框有两种方式,一种是继承于 Dialog 来定义一个子类实现弹框效果,一种是创建一个 新的 StatelessWidget(页面)。
实际上 Flutter 提供的 Dialog 也是继承于 StatelessWidget而实现的。
如下图所示中,定义一个基本的弹出层,除去下图中的中间的模糊部分
import 'package:flutter/material.dart';
/**
* 公共弹框
*/
class CommonDialog extends Dialog {
//子布局
Widget childWidget;
//左侧按钮显示文案
String negativeText;
//右侧按钮显示文案
String positiveText;
//标题显示文案
String title;
//显示标题下的分隔线
bool isShowTitleDivi;
//显示底部确认按钮上的分隔线
bool isShowBottomDivi;
//左侧按钮点击事件(取消)
Function onCloseEvent;
//右侧按钮点击事件(确认)
Function onPositivePressEvent;
//标题默认高度
double defaultTitleHeight = 40.0;
CommonDialog({
Key key,
@required this.childWidget,
@required this.title = "提示",
this.negativeText,
this.positiveText,
this.onPositivePressEvent,
this.isShowTitleDivi=true,
this.isShowBottomDivi=true,
@required this.onCloseEvent,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Padding(
padding: const EdgeInsets.all(10.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: Container(
height: defaultTitleHeight,
child: Center(
child: new Text(
title,
style: new TextStyle(
fontSize: 16.0, color: Color(0xff666666)),
),
),
),
),
//标题下的分隔线
new Container(
color: isShowTitleDivi?Color(0xffe0e0e0):Color(0xffffffff),
margin: EdgeInsets.only(bottom: 10.0),
height: 1.0,
),
//中间显示的Widget
new Container(
constraints: BoxConstraints(minHeight: 80.0),
child: new Padding(
padding: const EdgeInsets.all(12.0),
child: childWidget,
),
),
//底部的分隔线
new Container(
color: isShowBottomDivi?Color(0xffe0e0e0):Colors.white,
margin: EdgeInsets.only(top: 10.0),
height: 1.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 Container(
height: 54.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: widgets,
),
);
}
Widget _buildBottomCancelButton() {
return new FlatButton(
onPressed: onCloseEvent,
child: new Text(
negativeText,
style: TextStyle(
fontSize: 16.0,
color: Colors.grey,
),
),
);
}
Widget _buildBottomPositiveButton() {
return new FlatButton(
onPressed: onPositivePressEvent,
child: new Text(
positiveText,
style: TextStyle(
color: Colors.red,
fontSize: 16.0,
),
),
);
}
}
//是否满意标识位记录
int pariseSelectIndex = 0;
//不满意原因标识位记录
int pariseSelectIndex2 = 0;
//在按钮点击的时候直接调用
void showPariseDialog() {
showDialog<Null>(
context: context,
//点击背景不消失
barrierDismissible: false,
builder: (context) {
//StatefulBuilder 来构建 dialog
//使用参数 state来更新 dialog 中的数据内容
return StatefulBuilder(builder: (context, state) {
//创建dialog
return new CommonDialog(
title: "服务完成给个好平吧!",
negativeText: "取消",
positiveText: "确认",
isShowTitleDivi: false,
onPositivePressEvent: () {
print("确认 关闭");
Navigator.pop(context);
},
onCloseEvent: () {
print("取消 关闭");
Navigator.pop(context);
},
//通过state来刷新内容
childWidget: buildPariseChildDialog(state),
);
});
});
}
Widget buildPariseChildDialog(state){
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
//填充
mainAxisSize: MainAxisSize.max,
//平分空白
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildPariseChildWidget(
0, "非常满意", pariseSelectIndex == 0 ? true : false,state),
buildPariseChildWidget(
1, "满意", pariseSelectIndex == 1 ? true : false,state),
buildPariseChildWidget(
2, "不满意", pariseSelectIndex == 2 ? true : false,state),
],
),
pariseSelectIndex==2?gridViewDefaultCount(state):Container(),
],
);
}
//分析文章在这里 https://blog.csdn.net/zl18603543572/article/details/95037826
Widget buildPariseChildWidget(int index, String message, bool select,state) {
return Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(left: 5.0, right: 5.0),
//设置 child 居中
alignment: Alignment(0, 0),
height: 30,
child: new Center(
child: new Material(
child: new Ink(
key: ValueKey(index),
//设置背景
decoration: new BoxDecoration(
//背景
color: Colors.white,
//设置四周圆角 角度 这里的角度应该为 父Container height 的一半
borderRadius: BorderRadius.all(Radius.circular(15.0)),
//设置四周边框
border: new Border.all(
width: 1, color: select ? Colors.red : Colors.grey),
),
child: new InkResponse(
borderRadius: new BorderRadius.all(new Radius.circular(15.0)),
//点击或者toch控件高亮时显示的控件在控件上层,水波纹下层
highlightColor: Color(0xfffbfbfb),
//点击或者toch控件高亮的shape形状
highlightShape: BoxShape.rectangle,
//.InkResponse内部的radius这个需要注意的是,我们需要半径大于控件的宽,如果radius过小,显示的水波纹就是一个很小的圆,
//水波纹的半径
radius: 0.0,
//水波纹的颜色 设置了highlightColor属性后 splashColor将不起效果
splashColor: Color(0xfffbfbfb),
//true表示要剪裁水波纹响应的界面 false不剪裁 如果控件是圆角不剪裁的话水波纹是矩形
containedInkWell: true,
onTap: () {
pariseSelectIndex = index;
print('click ' + pariseSelectIndex.toString());
state(() {});
},
child: new Container(
//不能在InkResponse的child容器内部设置装饰器颜色,否则会遮盖住水波纹颜色的,containedInkWell设置为false就能看到是否是遮盖了。
width: 300.0,
height: 50.0,
//设置child 居中
alignment: Alignment(0, 0),
child: Text(
message,
style: TextStyle(
color: select ? Colors.red : Colors.grey,
fontSize: 14.0),
),
),
),
),
),
),
),
);
}
Widget gridViewDefaultCount(state) {
int count = 3;
double height = 60;
return Container(
margin: EdgeInsets.only(top: 20),
//设置 child 居中
alignment: Alignment(0, 0),
height: height,
//边框设置
decoration: new BoxDecoration(
//背景
color: Color(0xfff6f6f6),
//设置四周圆角 角度
borderRadius: BorderRadius.all(Radius.circular(4.0)),
//设置四周边框
border: new Border.all(width: 1, color: Color(0xfff6f6f6)),
),
child: initListWidget(count,state),
);
}
Widget initListWidget(int count,state) {
List<Widget> lists = [];
List<Widget> clists = [];
lists.add(buildPariseSelectChildWidget(
0, "出车慢", pariseSelectIndex2 == 0 ? true : false,state));
lists.add(buildPariseSelectChildWidget(
1, "服务差", pariseSelectIndex2 == 1 ? true : false,state));
lists.add(buildPariseSelectChildWidget(
2, "态度不好", pariseSelectIndex2 == 2 ? true : false,state));
clists.add(Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: lists,
));
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: clists,
);
}
Widget buildPariseSelectChildWidget(int index, String message, bool select,state) {
return InkWell(
//单击事件响应
onTap: () {
pariseSelectIndex2 = index;
state(() {});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.asset(
select
? ImageUtil.getImgsPath("phone_select_icon")
: ImageUtil.getImgsPath("phone_noselect_icon"),
width: 20.0,
height: 20.0,
),
Padding(
child: Text(
message,
style: TextStyle(fontSize: 13, color: Color(0xff666666)),
),
padding: EdgeInsets.only(left: 5.0),
)
],
),
);
}