Flutter实现两侧半圆切角样式优惠券详情Dialog方案
实现两侧带半圆切角的Dialog方案
自定义裁剪方案(推荐)
直接通过CustomClipper绘制带半圆切角的路径,效果精准无适配问题:
1. 定义裁剪器
class CouponClipper extends CustomClipper<Path> { final double radius; CouponClipper(this.radius); @override Path getClip(Size size) { final path = Path(); // 左上角起点 path.moveTo(radius, 0); // 上边线 path.lineTo(size.width - radius, 0); // 右上角半圆 path.arcToPoint(Offset(size.width, radius), radius: Radius.circular(radius)); // 右边线 path.lineTo(size.width, size.height - radius); // 右下角半圆 path.arcToPoint(Offset(size.width - radius, size.height), radius: Radius.circular(radius)); // 下边线 path.lineTo(radius, size.height); // 左下角半圆 path.arcToPoint(Offset(0, size.height - radius), radius: Radius.circular(radius)); // 左边线 path.lineTo(0, radius); // 左上角半圆闭合路径 path.arcToPoint(Offset(radius, 0), radius: Radius.circular(radius)); return path; } @override bool shouldReclip(CouponClipper oldClipper) => oldClipper.radius != radius; }
2. 在Dialog中使用
showDialog( context: context, builder: (context) => Dialog( backgroundColor: Colors.transparent, // 透明背景避免默认圆角干扰 child: ClipPath( clipper: CouponClipper(20), // 传入半圆半径 child: Container( color: Colors.white, padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 这里放你的优惠券详情内容 const Text("优惠券详情"), // 其他组件... ], ), ), ), ), );
替代方案:自定义ShapeBorder
如果不想用ClipPath,可以通过自定义ShapeBorder直接设置Dialog的shape属性:
class CouponShapeBorder extends RoundedRectangleBorder { final double radius; CouponShapeBorder(this.radius); @override Path getOuterPath(Rect rect, {TextDirection? textDirection}) { final path = Path(); path.moveTo(radius, rect.top); path.lineTo(rect.width - radius, rect.top); path.arcToPoint(Offset(rect.width, rect.top + radius), radius: Radius.circular(radius)); path.lineTo(rect.width, rect.bottom - radius); path.arcToPoint(Offset(rect.width - radius, rect.bottom), radius: Radius.circular(radius)); path.lineTo(radius, rect.bottom); path.arcToPoint(Offset(0, rect.bottom - radius), radius: Radius.circular(radius)); path.lineTo(0, rect.top + radius); path.arcToPoint(Offset(radius, rect.top), radius: Radius.circular(radius)); return path; } }
使用时直接设置Dialog的shape:
showDialog( context: context, builder: (context) => Dialog( shape: CouponShapeBorder(20), child: Container( padding: const EdgeInsets.all(16), child: // 优惠券详情内容 ), ), );
为什么Stack+Positioned方案效果不好?
这种方式是用背景色块覆盖默认Dialog的边角,不仅容易出现边缘锯齿、适配不同屏幕时错位,还会增加不必要的组件层级,自定义裁剪是直接绘制目标路径,视觉效果更精准。
内容的提问来源于stack exchange,提问作者RahulZx
相关产品推荐
相关产品推荐

