如何使用CustomClipper实现文件夹样式的卡片裁剪效果?
如何使用CustomClipper实现文件夹样式的卡片裁剪效果?
嗨,这个需求我刚好做过!要实现带顶部小标签的圆角矩形(文件夹样式),用CustomClipper完全可以搞定,我给你分享一下具体的实现代码和思路~
核心思路
其实就是通过Path手动拼接出文件夹的形状:底部是一个圆角矩形,顶部中间延伸出一个小标签,把这些点用直线和圆弧连起来就行。关键是要计算好各个点的坐标,确保路径闭合且平滑。
完整代码实现
首先定义自定义的Clipper:
import 'dart:math' as math; import 'package:flutter/material.dart'; class FolderClipper extends CustomClipper<Path> { final double radius; final double tabWidth; final double tabHeight; FolderClipper({ this.radius = 16.0, this.tabWidth = 60.0, this.tabHeight = 12.0, }); @override Path getClip(Size size) { final path = Path(); final halfTabWidth = tabWidth / 2; final centerX = size.width / 2; // 1. 移动到标签的左上角 path.moveTo(centerX - halfTabWidth, 0); // 2. 画标签的顶部横线到右上角 path.lineTo(centerX + halfTabWidth, 0); // 3. 画标签的右侧竖线到右下角 path.lineTo(centerX + halfTabWidth, tabHeight); // 4. 画右上角的圆角 path.arcTo( Rect.fromLTWH(size.width - radius, tabHeight, radius, radius), 0.0, math.pi / 2, false, ); // 5. 画右侧竖线到底部 path.lineTo(size.width, size.height - radius); // 6. 画右下角的圆角 path.arcTo( Rect.fromLTWH(size.width - radius, size.height - radius, radius, radius), 0.0, math.pi / 2, false, ); // 7. 画底部横线到左侧 path.lineTo(radius, size.height); // 8. 画左下角的圆角 path.arcTo( Rect.fromLTWH(0, size.height - radius, radius, radius), math.pi / 2, math.pi / 2, false, ); // 9. 画左侧竖线到顶部 path.lineTo(0, tabHeight + radius); // 10. 画左上角的圆角 path.arcTo( Rect.fromLTWH(0, tabHeight, radius, radius), math.pi, math.pi / 2, false, ); // 11. 画直线到标签的左下角 path.lineTo(centerX - halfTabWidth, tabHeight); // 12. 闭合路径 path.close(); return path; } @override bool shouldReclip(covariant FolderClipper oldClipper) { // 当参数变化时重新裁剪 return radius != oldClipper.radius || tabWidth != oldClipper.tabWidth || tabHeight != oldClipper.tabHeight; } }
然后是使用示例:
ClipPath( clipper: FolderClipper( radius: 18.0, // 自定义圆角大小 tabWidth: 70.0, // 标签宽度 tabHeight: 14.0, // 标签高度 ), child: Container( width: 300, height: 200, padding: const EdgeInsets.only(top: 20), // 注意给顶部标签留出空间,避免内容被遮挡 decoration: BoxDecoration( color: Colors.blue[100], boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: const Center( child: Text('文件夹样式卡片'), ), ), )
关键细节说明
- 参数可自定义:你可以通过调整
radius、tabWidth、tabHeight这三个参数,来适配不同大小的卡片和标签样式,非常灵活。 - 路径闭合:最后一定要调用
path.close(),确保路径是闭合的,不然裁剪出来的形状可能会有缺口。 - 内容边距:因为顶部有个标签,所以Container的
padding要给顶部留出足够的空间(比如比tabHeight大一点),避免内容被标签的区域遮挡。 - arcTo的用法:每个圆角都是用
arcTo画的,需要注意外接矩形的位置和角度参数,确保圆角的方向正确。比如右上角的圆角,外接矩形是从size.width - radius开始,宽高都是radius,角度从0到π/2(也就是从右向下转90度)。
如果想给顶部标签也加圆角,只需要把画标签的直线换成圆弧就行,比如把步骤2和3改成画圆角,调整起来也很方便~




