如何实现如图所示的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
相关产品推荐
相关产品推荐

