「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」
自定义dialog
先来看看一个示例
class ExamResultDialog extends Dialog{
...
@override
Widget build(BuildContext context) {
return new ExamResultDialogContent(entity, listener);
}
}
class ExamResultDialogContent extends StatefulWidget{
...
@override
State<StatefulWidget> createState() {
...
return _ExamResultDialogContent();
}
...
}
class _ExamResultDialogContent extends State<ExamResultDialogContent>{
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20)),
),
width: 752,
height: 426,
child: ..., //内容部分
),
),
);
}
}
从上面可以看到先继承dialog,在它的build函数然后widget,剩下的与正常的widget差不多。
但是注意几点:
- 最外层需要用Scaffold包裹,否则所有默认样式都会失效。
- 使用Scaffold后,背景是不透明的,需要再设置backgroundColor为透明的。
- dialog默认是全屏的,所以需要用Container来限制内容的大小,并用Center包裹使内容居中。同时也可以对Container添加decoration实现弹窗背景
大小动态调整的Dialog
开发中经常遇到这样的dialog,内容变化很大,所以dialog的大小也要跟着变化,但是为了美观又不能太大,当内容过多的时候dialog大小就不再改变,而是内容可滚动查看。
下面我们一步步实现这个dialog
Text内容可滚动
这里同时也解决Text显示不全的问题。
我们用最简单的dialog,内容只有文字,那么第一步要解决的就是如果文字特别多的情况下,怎么让Text的内容可以滚动。
答案是用SingleChildScrollView,它只有一个child,作用就是如果child太大的情况下可以滚动查看。
代码:
SingleChildScrollView(
child: Text(
widget.msg,
style:TextStyle(color: Color(0xff919294), fontSize: 18),
),
但是这里有一个问题,就是虽然能滚动了,但是Text显示不全,现象是当Text文字内容很多的时候,最后一行看不到,而倒数第二行只能显示一半。
这个不是SingleChildScrollView的问题,经测试,在空白页面上单独使用Text,高度不限,依然会出现这样的情况,甚至Text下半部分还空白着,后面的文字依然不显示。
注意:这个情况是发生在flutter web,在chrome上出现,在Android或ios未测试,可能是web特有的问题
经过反复尝试,最终发现为Text设置overflow: TextOverflow.ellipsis可以解决,文字可以完整显示出来了。
overflow的作用就是文字显示不下时采用什么样的处理,ellipsis就是省略,还有shape(渐变)、visible等等。这里不知道为什么设置ellipsis可以起作用,反而设置visible不行。
但是设置overflow: TextOverflow.ellipsis可以解决单独使用Text时的问题,如果使用SingleChildScrollView嵌套到达滚动效果的话,Text只显示一行。。。
这里我的解决方法时设置Text的maxLines: 100 这里的100只是一个较大的数,可以是1000,只有保证内容完全显示即可。
这个解决方案并不理想,但是暂时只想到这个解决方案。最终代码:
SingleChildScrollView(
child: Text(
widget.msg,
overflow: TextOverflow.ellipsis,
maxLines: 100,
style:TextStyle(color: Color(0xff919294), fontSize: 18),
),
窗口大小动态调整并限制最大高度
这里使用LimitedBox来实现高度的限制,直接上代码:
SizedBox(
width: 400,
child: Container(
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
child: Text(
"公告",
style: TextStyle(color: Color(0xff212223), fontSize: 24),
),
width: double.infinity,
alignment: Alignment.center,
margin: EdgeInsets.only(top: 10, bottom: 20),
),
LimitedBox(
maxHeight: 400,
child: SingleChildScrollView(
child: Text(
widget.msg,
overflow: TextOverflow.ellipsis,
maxLines: 100,
style:
TextStyle(color: Color(0xff919294), fontSize: 18),
),
padding: EdgeInsets.only(left: 20, right: 20),
),
),
Padding(padding: EdgeInsets.all(10))
],
),
GestureDetector(
child: Container(
child: Image.asset(
R.assetsAlertClose,
width: 20,
height: 20,
),
padding: EdgeInsets.all(10),
alignment: Alignment.topRight,
),
onTap: () {
Navigator.of(context).pop();
},
)
],
),
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.all(
Radius.circular(13),
),
),
),
));
最外层是一个SizedBox,目的是设置窗口的宽度,这个是固定的,而窗口的高度是动态的。 然后就遇到了第一个问题,一开始我在第二层就使用LimitedBox,如下:
SizedBox(
width: 400,
child: LimitedBox(
maxHeight: 400,
child: Container(
...
但是这样无论Container内容有多大,Container高度(甚至里面没有任何内容)都一直是400,而我们期望的是Container高度可以随着内容变化,而最大高度限制在400
经过尝试,将LimitedBox放在Container里层即可,具体原因还不得而知,Flutter UI嵌套感觉问题一直很多。
最终结果就像上面一样,只在内容部分的外层套一层LimitedBox来限制最大高度,这样就实现了动态变化且有最大限制。
这里还要注意,在Column中我设置了mainAxisSize: MainAxisSize.min 因为默认Column是在垂直方向上是完全展开的,这样高度就不能动态变化了,所以这里的设置让Column垂直方向上根据内容展示即可。
在flutter中由于各种ui的嵌套和各种默认值,做一些大小动态调整的组件还是需要一些工作量,要注意一些坑。