前因
项目开发中总有一些常用的界面,需求能够重复运用,于是,有了这篇文章,期望作用如下:
需求分析
- 底部撤销按钮,字体色彩独自显现
- 选项按钮并排显现,可能存在多个
- 挑选后需求有对应的成果回来
- 整个弹窗背景色通明
根据以上需求,规划组件需求开放的属性如下:
final String cancelTitle;//撤销按钮标题
final String? title;//提示标题,此版本暂未完成显现标题
final List<String> actions;//选项按钮标题
final Color? cancelColor;//撤销按钮色彩
final Color? titleColor;//标题色彩
final Color? actionColor;//选项标题色彩
final Color bgColor;//选项卡背景色
final String? fontFamily;//字体
final double fontSize;//字号
final double selectionHeight;//每个选项的高度
final double borderRadius;//圆角巨细
final FontWeight fontWeight;//字重
final ValueChanged<int>? selectAction;//选项成果回调
作用完成
拆分模块:
- 整体运用一个SizeBox包装,控制组件巨细
- 整体展现方式为列表,先用一个Column包装
- 考虑到上层选项卡共用一个圆角和基层选项卡独自一个圆角,将运用两个Column将上基层拆分
- 圆角作用则用ClipRRect包裹
- 每个选项卡选中事情则直接用
GestureDetector
包装,回来点击事情 - 考虑到每个选项卡有背景色,一切用
Container
包裹一下,展现背景色 - 文字显现部分则直接运用
Text
这儿用的SVText
是对Text组件的封装,是为了便于开发和后期的修正,其本质便是一个Text,开放了一些常用属性。
上代码:
Widget build(BuildContext context) {
// TODO: implement build
double width = MediaQuery.of(context).size.width*0.9;//计算需求展现的宽度
double safeBottomHeight = MediaQuery.of(context).padding.bottom;//底部需求留出安全区的位置
double space = 10;//撤销选项和其他选项的距离
return SizedBox(//运用SizeBox进行包装
width: width,//宽
height: (selectionHeight + 1)*(actions.length + 1) + safeBottomHeight + space,//高
child: Column(//分层
children: [
ClipRRect(//上层圆角
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),//圆角
child: Column(//上层显现按钮
//这儿为了减少代码量,则直接将生成选项卡的代码逻辑封装了一下
children: getActionSheet(context),
),
),
Padding(//上层和撤销选项距离
padding: EdgeInsets.only(top: space),
),
ClipRRect(//基层圆角
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
//封装选项卡生成函数
child: getSelectWidget(cancelTitle, true, -1,context),
),
Padding(
padding: EdgeInsets.only(top: safeBottomHeight),
),
],
)
);
}
//回来上层选项卡一切的视图
List<Widget> getActionSheet(BuildContext context){
List<Widget> actionsWidget = [];
for (int i = 0;i < actions.length; i ++){
String title = actions[i];
//生成上层每个选项卡
GestureDetector action = getSelectWidget(title, false, i, context);
actionsWidget.add(action);
if (i < actions.length - 1){
Padding padding = const Padding(
padding: EdgeInsets.only(top: 1)
);
actionsWidget.add(padding);
}
}
return actionsWidget;
}
//选项卡生成函数
GestureDetector getSelectWidget(String title, bool isCancel, int tag, BuildContext context){
return GestureDetector(//点击事情包裹
child: Container(
height: selectionHeight,
width: double.infinity,
color: bgColor,
alignment: Alignment.center,
child: SSLText(
text: title,
textColor: isCancel?cancelColor:actionColor,
fontSize: fontSize,
fontWeight: fontWeight,
textDecoration: TextDecoration.none,
),
),
onTap: (){
//点击回调事情
if (selectAction != null){
selectAction!(tag);
}
//由于选用的是弹窗方式,则可运用pop获取回来值
Navigator.of(context).pop(tag);
},
);
}
至此弹窗根本封装结束。由于现在未涉及到运用标题的弹窗,标题功能暂未开发。
弹窗运用
弹窗封装完成后还需求有函数去展现这个弹窗,这儿参考Flutter 对话框和Flutter 弹窗款式。
最后挑选运用showCupertinoModalPopup
,这个弹窗的作用和iOS类似,只需将封装好的弹窗传递过去就好,剩下的动画作用和回来值系统现已处理好,直接用就行了。
上代码:
static Future<int> showBottomSheet(BuildContext context,
{ required List<String> actions,
required String cancelTitle,
Color? titColor,
Color? cancelColor,
Color? actionColor,
double? fontSize,
String? fontFamily,
double? selectionHeight,
double? borderRadius,
Color? bgColor,
String? title,
ValueChanged? selection,
})async {
//通过系统获取回来值,具体的能够研讨下弹窗的原理,这个便是获取上面pop的回来值
var result = await showCupertinoModalPopup(context: context, builder: (context){
return SSLSheetAlert(//封装好的弹窗
actions: actions,
cancelTitle: cancelTitle,
selectAction: selection,
titleColor: titColor,
cancelColor: cancelColor,
actionColor: actionColor,
fontSize: fontSize ?? 16,
fontFamily: fontFamily,
selectionHeight: selectionHeight??50,
borderRadius: borderRadius??8,
bgColor: bgColor??Colors.white,
title: title,
);
});
//需求额定处理的是,假如直接点击背景罩,此刻回来的是null,所以这儿需求特殊判断一下
if (result == null){
return -1;
}
return result;
}
终究用法:
//获取系统回来成果
int result = await UIAlertTool.svShowBottomSheet(
context,
actions:["男", "女"],
cancelTitle: "撤销",
actionColor: Colors.green,
cancelColor: Colors.red,
selection: (value){
获取回调成果
debugPrint("ssl get result 11 $value");
}
);
debugPrint("ssl get result $result");
终究作用:
iOS
Android
注意:
在没有运用Material的时分,Text文本显现会和运用Material有差异,说下两个点:
- 没有运用的时分文本下面会有黄色的下划线,此刻需求运用TextStyle中的
decoration
属性,设置为TextDecoration.none
。 - 字重在没有运用Material的时分会加粗,这个时分需求设置一下字重,通常设置为
FontWeight.w500
。