如何在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
相关产品推荐
相关产品推荐

