如何在Flutter中制作这类镂空圆形效果?
Flutter实现镂空圆形效果的解决方案
要实现透明镂空的圆形效果,Stack直接叠加无法达到“挖洞”的效果,需要通过自定义绘制或裁剪来实现,以下是两种实用方案:
方案一:CustomPaint自定义绘制(推荐)
通过CustomPaint先绘制背景层,再用BlendMode.clear挖去圆形区域,让下方内容透出:
自定义Widget代码
class HollowCircleWidget extends StatelessWidget { final double size; final Color backgroundColor; final double circleRadius; const HollowCircleWidget({ super.key, required this.size, required this.backgroundColor, required this.circleRadius, }); @override Widget build(BuildContext context) { return CustomPaint( size: Size(size, size), painter: _HollowCirclePainter( bgColor: backgroundColor, circleRadius: circleRadius, ), ); } } class _HollowCirclePainter extends CustomPainter { final Color bgColor; final double circleRadius; _HollowCirclePainter({required this.bgColor, required this.circleRadius}); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final paint = Paint()..color = bgColor; // 绘制全屏背景 canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint); // 使用清除模式挖去圆形区域 paint.blendMode = BlendMode.clear; canvas.drawCircle(center, circleRadius, paint); } @override bool shouldRepaint(covariant _HollowCirclePainter oldDelegate) { return oldDelegate.bgColor != bgColor || oldDelegate.circleRadius != circleRadius; } }
使用示例
Stack( alignment: Alignment.center, children: [ // 下方需要透出的内容(图片/容器等) Image.asset('assets/background.jpg'), // 镂空圆形遮罩 HollowCircleWidget( size: 300, backgroundColor: Colors.black.withOpacity(0.6), circleRadius: 80, ), ], )
方案二:ClipPath裁剪实现
通过ClipPath创建带镂空的路径,利用PathFillType.evenOdd实现区域镂空:
自定义裁剪器代码
class HollowCircleClipper extends CustomClipper<Path> { final double circleRadius; HollowCircleClipper({required this.circleRadius}); @override Path getClip(Size size) { final center = Offset(size.width / 2, size.height / 2); final path = Path() // 添加整个容器区域 ..addRect(Rect.fromLTWH(0, 0, size.width, size.height)) // 添加圆形区域(会被镂空) ..addOval(Rect.fromCircle(center: center, radius: circleRadius)); // 设置填充模式为奇偶规则,重叠区域会被裁剪 path.fillType = PathFillType.evenOdd; return path; } @override bool shouldReclip(covariant HollowCircleClipper oldClipper) { return oldClipper.circleRadius != circleRadius; } }
使用示例
Stack( alignment: Alignment.center, children: [ // 下方需要透出的内容 Container(color: Colors.blueAccent), // 镂空遮罩 ClipPath( clipper: HollowCircleClipper(circleRadius: 80), child: Container( width: 300, height: 300, color: Colors.black.withOpacity(0.6), ), ), ], )
扩展说明
- 如果需要多个镂空圆形,只需在绘制逻辑中添加多个
drawCircle(方案一)或addOval(方案二)即可。 - 使用
BlendMode.clear时,部分Web环境可能需要额外配置渲染参数,移动端无特殊限制。
内容的提问来源于stack exchange,提问作者Farid Ahmadov
相关产品推荐
相关产品推荐

