背景:
showModalBottomSheet是系统提供的底部弹窗,但是正常情况高度是固定的。内容少的时候底部弹窗下面空一片不太好看。需要根据显示内容的高度来调整弹窗的高度。
showModalBottomSheet的isScrollControlled属性,设置为true,弹窗会覆盖整个手机。设置为false,弹窗大概是整个屏幕的9/16高。
ConstrainedBox 这是一个可以限制子控件高度的控件。
思路:
由于我的弹窗里面主要是放了一个listview,所以我会在代码里面打印出list的的每一个item的高度。然后算出真个listview的高度。把isScrollControlled设置为true,在用ConstrainedBox限制listview的高度。这样listview多高,弹窗就是多高。
///项目通用的底部弹窗
void showBottomDialog(BuildContext context, List<String> list,Function onItem) async {
if ((list != null) && !list.contains('取消')) {
list.add('取消');
}
await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
//56
return ConstrainedBox(
constraints: BoxConstraints(maxHeight: getHeight(context, list)),
child: ListView.separated(
itemCount: list == null ? 0 : list.length,
separatorBuilder: (context, index) {
return Divider(
height: 0,
);
},
itemBuilder: (context, index) {
return ListTile(
title: GestureDetector(
child: Container(
color: Colors.transparent,
width: double.infinity,
height: 45,
alignment: Alignment.center,
child: Text(
list[index] ?? "",
style: textStyle_black,
),
),
onTap: () {
if (index == list.length - 1) {
Navigator.of(context).pop();
}else{
onItem(index);
}
},
),
);
},
),
);
});
}
double getHeight(BuildContext context, List<String> list) {
if (56.0 * (list?.length) > MediaQuery.of(context).size.height * 0.8) {
return MediaQuery.of(context).size.height * 0.8;
}
return 56.0 * (list?.length);
}
当有滚动布局的时候,需要设置isScrollControlled为true
下面是源码中对高度的限制,不设置只能是屏幕的9/16的高度。
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: 0.0,
maxHeight: isScrollControlled
? constraints.maxHeight
: constraints.maxHeight * 9.0 / 16.0,
);
}
少量列表
item_less.png
大量列表最大直到屏幕的80%
item-more.png
二、重新实现
上面是初学时候写的,现在根据简友的评论重新写了下,之所以没有删除上面的,是因为上面还是有些知识点的。实用直接拿下面的代码。
///项目通用的底部弹窗
void showBottomDialog(
BuildContext context, List<String?> list, Function onItem) async {
double maxShowHeight = MediaQuery.of(context).size.height * 0.8;
double itemHeight = 56.h;
Widget listView() {
return ListView.separated(
shrinkWrap: true,
itemCount: list.length,
separatorBuilder: (context, index) {
return Divider(
height: 1,
color: fillColor,
);
},
itemBuilder: (context, index) {
return GestureDetector(
child: Container(
color: Colors.white,
width: double.infinity,
height: 56.h,
alignment: Alignment.center,
child: Text(
list[index] ?? "",
style: styleBlack_16,
),
),
onTap: () {
onItem(index);
Navigator.of(context).pop();
},
);
},
);
}
Widget cancelWidget() {
return GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Container(
color: Colors.white,
margin: EdgeInsets.only(top: 8.h),
height: 54.h,
width: 1.sw,
alignment: Alignment.center,
child: Text(
"取消",
style: styleBlack_16,
),
));
}
await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxShowHeight),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
list.length >= maxShowHeight / itemHeight ? Expanded(child: listView()) : listView(),
cancelWidget(),
],
),
);
});
}