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

如何实现如图所示的Flutter自定义Container组件?

实现自定义形状Container的方案

针对你需要的异形容器,推荐使用ClipPath+自定义CustomClipper的方式,比CustomPaint更适配Container的使用逻辑,以下是可直接运行的代码:

import 'package:flutter/material.dart';

class CustomNotchedContainer extends StatelessWidget {
  final Widget child;
  final Color backgroundColor;
  final double cornerRadius;
  final double notchWidth; // 顶部缺口的宽度

  const CustomNotchedContainer({
    Key? key,
    required this.child,
    this.backgroundColor = Colors.white,
    this.cornerRadius = 12.0,
    this.notchWidth = 24.0,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: _NotchedContainerClipper(
        cornerRadius: cornerRadius,
        notchWidth: notchWidth,
      ),
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
        color: backgroundColor,
        child: child,
      ),
    );
  }
}

class _NotchedContainerClipper extends CustomClipper<Path> {
  final double cornerRadius;
  final double notchWidth;

  _NotchedContainerClipper({
    required this.cornerRadius,
    required this.notchWidth,
  });

  @override
  Path getClip(Size size) {
    final path = Path();

    // 绘制顶部左侧缺口
    path.moveTo(notchWidth, 0);
    // 右上角圆角
    path.lineTo(size.width - cornerRadius, 0);
    path.arcToPoint(
      Offset(size.width, cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    // 右下角圆角
    path.lineTo(size.width, size.height - cornerRadius);
    path.arcToPoint(
      Offset(size.width - cornerRadius, size.height),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    // 左下角圆角
    path.lineTo(cornerRadius, size.height);
    path.arcToPoint(
      Offset(0, size.height - cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    // 左上角圆角后连接到缺口起点
    path.lineTo(0, cornerRadius);
    path.arcToPoint(
      Offset(cornerRadius, 0),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.lineTo(notchWidth, 0);

    return path;
  }

  @override
  bool shouldReclip(covariant _NotchedContainerClipper oldClipper) {
    return cornerRadius != oldClipper.cornerRadius ||
        notchWidth != oldClipper.notchWidth;
  }
}

// 使用示例
void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.grey.shade200,
        body: Center(
          child: CustomNotchedContainer(
            notchWidth: 28,
            child: const Text(
              "自定义容器示例",
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
            ),
          ),
        ),
      ),
    );
  }
}

说明

  • 通过调整notchWidth参数可以控制顶部左侧缺口的宽度,完全匹配你需要的样式
  • 容器支持添加任意子组件,也可以把color替换为decoration来实现渐变、边框等效果
  • 相比Stack堆叠组件的方式,ClipPath直接裁剪容器轮廓,不会出现层级错乱或者适配问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:33:59