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

如何在Flutter中使用Container实现图片所示的自定义形状?

Flutter 实现自定义形状 Container

要做出你需要的自定义形状,Container组件本身无法直接实现复杂的自定义轮廓,得借助Flutter的自定义裁剪或者自定义形状装饰来实现。下面提供两种常用方案,以你图片里的顶部中间带凹口的形状为例(如果是其他形状,只需调整路径即可):

方案一:使用 ShapeDecoration + 自定义 ShapeBorder

这种方式可以直接给Container的decoration属性设置自定义形状,代码更贴合Container的使用习惯:

class CustomNotchShape extends ShapeBorder {
  final double notchRadius;

  CustomNotchShape({this.notchRadius = 20.0});

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) => getOuterPath(rect, textDirection: textDirection);

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    final centerX = rect.center.dx;
    return Path()
      // 从左上角开始
      ..moveTo(rect.left, rect.top)
      // 画到凹口左侧起点
      ..lineTo(centerX - notchRadius, rect.top)
      // 绘制向下凹的圆弧
      ..arcToPoint(
        Offset(centerX + notchRadius, rect.top),
        radius: Radius.circular(notchRadius),
        clockwise: false,
      )
      // 画到右上角
      ..lineTo(rect.right, rect.top)
      // 画到右下角
      ..lineTo(rect.right, rect.bottom)
      // 画到左下角
      ..lineTo(rect.left, rect.bottom)
      // 闭合路径
      ..close();
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}

  @override
  ShapeBorder scale(double t) => CustomNotchShape(notchRadius: notchRadius * t);
}

使用示例

Container(
  width: 320,
  height: 200,
  decoration: ShapeDecoration(
    color: Colors.deepPurpleAccent,
    shape: CustomNotchShape(notchRadius: 35),
    // 可选:添加阴影
    shadows: [
      BoxShadow(
        color: Colors.grey.withOpacity(0.3),
        blurRadius: 8,
        offset: Offset(0, 4),
      )
    ],
  ),
  child: const Center(
    child: Text(
      "自定义形状容器",
      style: TextStyle(color: Colors.white, fontSize: 19),
    ),
  ),
)

方案二:使用 ClipPath 裁剪容器

如果只需要单纯裁剪UI,ClipPath是更轻量的选择:

class NotchClipper extends CustomClipper<Path> {
  final double notchRadius;

  NotchClipper({this.notchRadius = 20.0});

  @override
  Path getClip(Size size) {
    final centerX = size.width / 2;
    return Path()
      ..moveTo(0, 0)
      ..lineTo(centerX - notchRadius, 0)
      ..arcToPoint(
        Offset(centerX + notchRadius, 0),
        radius: Radius.circular(notchRadius),
        clockwise: false,
      )
      ..lineTo(size.width, 0)
      ..lineTo(size.width, size.height)
      ..lineTo(0, size.height)
      ..close();
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

使用示例

ClipPath(
  clipper: NotchClipper(notchRadius: 35),
  child: Container(
    width: 320,
    height: 200,
    color: Colors.deepPurpleAccent,
    child: const Center(
      child: Text(
        "自定义形状容器",
        style: TextStyle(color: Colors.white, fontSize: 19),
      ),
    ),
  ),
)

调整形状适配你的需求

如果你的目标形状不是顶部凹口,只需要修改Path里的绘制逻辑即可:

  • 要做斜切角:用lineTo直接连接斜角的坐标点
  • 要做其他圆弧缺口:调整arcToPoint的参数和路径顺序
  • 要做复杂多边形:依次添加多个lineTo点后闭合路径

内容的提问来源于stack exchange,提问作者VolkanUstekidag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:05:31