Flutter 如何实现顶部对齐Dialog与叠加虚线UI效果
Flutter 自定义Dialog位置与叠加虚线效果实现
请问如何实现对应的目标UI效果?目前开发过程中遇到两个实现卡点:
- 无法对弹出的Dialog自定义对齐规则(gravity)与展示位置
- 不清楚如何实现面板上下叠加的虚线分隔效果
现有功能代码如下:
class DashboardScreen extends StatefulWidget { @override _DashboardScreenState createState() => _DashboardScreenState(); } class _DashboardScreenState extends State<DashboardScreen> { @override Widget build(BuildContext context) { return Scaffold( body: Container(), appBar: AppBar( centerTitle: false, automaticallyImplyLeading: false, backgroundColor: Colors.white, elevation: 0, title: Text( "Inventory", textScaleFactor: 1.3, style: TextStyle(color: Colors.black87, fontFamily: "light"), ), actions: [ IconButton( onPressed: (){}, color: Colors.black, icon: ImageIcon( AssetImage('assets/images/camera_outline.png'), size:50, ), ), IconButton( onPressed: (){}, color: Colors.black, icon: ImageIcon( AssetImage('assets/images/camera_outline.png'), size:50, ), ), IconButton( onPressed: (){ // openAlertBox(); showDialog( context: context, builder: (_) => Dialog( backgroundColor: Colors.transparent, insetPadding: EdgeInsets.all(20), child: Column( children: <Widget>[ Container( width: double.infinity, height: 150, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Colors.white ), padding: EdgeInsets.fromLTRB(20, 50, 20, 20), child: Text( "You can make cool stuff!", style: TextStyle(fontSize: 24), textAlign: TextAlign.center ), ), ], ) ) ); }, color: Colors.black, icon: ImageIcon( AssetImage('assets/images/camera_outline.png'), size:50, ), ) ], ), ); } }
效果对比
目标UI参考效果:

目前已实现的效果:

实现方案
针对上述两个实现卡点,可通过原生Flutter能力完成开发,无需引入第三方依赖:
1. Dialog 自定义对齐与位置
默认Dialog为垂直居中展示,可通过Dialog自带的属性直接调整位置与对齐规则:
- 配置
alignment属性,直接指定Dialog在弹窗层的对齐关系,支持自定义坐标偏移实现任意位置定位 - 调整
insetPadding属性值,控制Dialog距离屏幕四边的留白,设为EdgeInsets.zero即可实现完全贴边无内边距
注意:Dialog本身不会对child组件做强制尺寸约束,只需要在child层根据需求设置宽高即可。
2. 叠加虚线效果
用Stack组件做分层布局,把虚线绘制层叠加在白色面板的对应位置即可,无需对面板做挖空处理。
虚线绘制可通过CustomPaint + 自定义CustomPainter实现,无需额外引入包依赖。
修改后的弹窗核心实现代码:
showDialog( context: context, builder: (_) => Dialog( backgroundColor: Colors.transparent, // 清除默认内边距 insetPadding: EdgeInsets.zero, // 自定义Dialog垂直位置,数值范围-1到1,-1为屏幕顶部,1为屏幕底部 alignment: const Alignment(0, -0.3), child: Stack( alignment: Alignment.center, children: [ // 白色内容主面板 Container( width: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.fromLTRB(20, 50, 20, 20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Colors.white, ), child: const Text( "You can make cool stuff!", style: TextStyle(fontSize: 24), textAlign: TextAlign.center, ), ), // 叠加层:分隔虚线 Positioned( top: 25, // 调整虚线的垂直位置 left: 40, right: 40, child: CustomPaint( size: const Size(double.infinity, 1), painter: DashedLinePainter(), ), ) ], ), ), );
虚线绘制的Painter实现:
class DashedLinePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final Paint paint = Paint() ..color = Colors.grey.shade300 ..strokeWidth = 1 ..strokeCap = StrokeCap.round; const double dashWidth = 5; const double dashSpace = 4; double startX = 0; while (startX < size.width) { canvas.drawLine( Offset(startX, 0), Offset(startX + dashWidth, 0), paint, ); startX += dashWidth + dashSpace; } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; }
内容的提问来源于stack exchange,提问作者Farhana Naaz Ansari
相关产品推荐
相关产品推荐

