自定义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的嵌套和各种默认值,做一些大小动态调整的组件还是需要一些工作量,要注意一些坑。