You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 10:55:25