1、前言
Flutter没有提供底部类似iOS的弹出框,或者是有但是我不知道,毕竟Widget太多,这里先上效果图,可以看下是否符合你的要求。
图1是iOS系统的效果,图2是我们实现的效果


2、控件介绍
- showModalBottomSheet
系统提供的底部弹出窗,这个弹出框默认是有高度的,代码和默认效果如下图
/// 点击事件
void _selectAction() async {
int index = await showActionSheets();
}
/// 弹窗
Future<int> showActionSheets()
{
return showModalBottomSheet<int>(
context: context,
builder: (BuildContext context){
return Container();
}
);
}

3、 具体实现
- 弹出窗底色为透明色,高度自适应
- 点击空白区域返回null,取消返回0,其他根据自身index返回
- 我们对效果进行了封装,并开放了一定的可定制性
创建类custom_action_sheet,代码如下
image.png
import 'package:flutter/material.dart';
// 弹出底部sheet
Future<int> showCustomBottomSheet({
@required BuildContext context,
double radiusSize = 5.0, // 默认圆角为5
double paddingSize = 10.0, // 默认左右间距为10
String title = '', // 标题
double titleFontSize = 14, // 标题字体大小
Color titleColor = Colors.red, // 标题默认颜色
String cancelTitle = '取消',
double cancelHeight = 45,
double cancelFontSize = 15,
Color cancelTextColor = Colors.black,
List<Widget> children = const <Widget>[],
})
{
assert(context != null);
return showModalBottomSheet<int>(
context: context,
backgroundColor: Color(0x00ffffff), // 背景色设置为无色
elevation: 0, // 透明度
builder: (BuildContext context) {
return GestureDetector(
onTap: (){
Navigator.pop(context,-1);
},
child: Container(
color: Color(0x00ffffff), // 设置颜色后点击事件才有效
alignment: Alignment.bottomCenter,
padding: EdgeInsets.fromLTRB(paddingSize, 0, paddingSize, MediaQuery.of(context).padding.bottom),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
GestureDetector(
onTap: (){},
child: Container(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: (children.length == 0) ? BorderRadius.all(Radius.circular(radiusSize))
: BorderRadius.only(topLeft: Radius.circular(radiusSize), topRight: Radius.circular(radiusSize))
),
alignment: Alignment.center,
constraints: BoxConstraints(
minHeight: 45,
),
child: Text(title, textAlign: TextAlign.center,style: TextStyle(color: titleColor, fontSize: titleFontSize),
),
),
),
Column(
children:children
),
Container(
height: 10,
),
GestureDetector(
onTap: (){
Navigator.pop(context,0);
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(radiusSize))
),
alignment: Alignment.center,
height: cancelHeight,
child: Text(cancelTitle,style: TextStyle(color: cancelTextColor,fontSize: cancelFontSize),),
),
),
],
)
),
);
},
);
}
/// 添加时候的item
Widget actionItem({
@required BuildContext context,
@required int index,
@required String title,
Color color = Colors.black,
Color backgroundColor = Colors.white,
double radiusSize = 5.0, // 默认圆角为5
bool isLastOne = false, // 是否为最后一个,最后一个如果有圆角的话需要增加底部圆角
double height = 45,
double fontSize = 15,
}){
assert(context != null);
assert(title != null);
assert(index > 0);
return GestureDetector(
onTap: (){
Navigator.pop(context,index);
},
child: Column(
children: <Widget>[
/// 分割线
Divider(
height: 0.5,
color: Color(0xffeeeeee),
),
Container(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: isLastOne ? BorderRadius.only(bottomLeft: Radius.circular(radiusSize), bottomRight: Radius.circular(radiusSize)) : BorderRadius.all(Radius.circular(0))
),
alignment: Alignment.center,
height: height,
child: Text(title,style: TextStyle(color: color, fontSize: fontSize),),
)
],
)
);
}
4、具体使用
import 'package:flutter/material.dart';
import '../../widgets/custom_action_sheet.dart';
class BottomSheetDialog extends StatefulWidget {
@override
_BottomSheetDialogState createState() => _BottomSheetDialogState();
}
class _BottomSheetDialogState extends State<BottomSheetDialog> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('弹出框'),
),
body: Container(
child: Center(
child: FlatButton(
onPressed: _selectAction,
child: Text('底部弹窗')
),
),
),
);
}
void _selectAction() async {
int index1 = await showPayActionSheets(context: context, title: '支付方式');
print(index1);
}
/// 具体使用方式
Future<int> showPayActionSheets({
@required BuildContext context,
@required String title,
})
{
return showCustomBottomSheet(
context: context,
title: title,
children: [
actionItem(context: context, index: 1, title: '微信支付'),
actionItem(context: context, index: 2, title: '支付宝支付',isLastOne: true),
]
);
}
}
5、遗留问题
- 1、item过多会爆越界错误,可以尝试将Column改成ListView
- 2、其他
网友评论