You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用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('文件夹样式卡片'),
    ),
  ),
)

关键细节说明

  • 参数可自定义:你可以通过调整radiustabWidthtabHeight这三个参数,来适配不同大小的卡片和标签样式,非常灵活。
  • 路径闭合:最后一定要调用path.close(),确保路径是闭合的,不然裁剪出来的形状可能会有缺口。
  • 内容边距:因为顶部有个标签,所以Container的padding要给顶部留出足够的空间(比如比tabHeight大一点),避免内容被标签的区域遮挡。
  • arcTo的用法:每个圆角都是用arcTo画的,需要注意外接矩形的位置和角度参数,确保圆角的方向正确。比如右上角的圆角,外接矩形是从size.width - radius开始,宽高都是radius,角度从0到π/2(也就是从右向下转90度)。

如果想给顶部标签也加圆角,只需要把画标签的直线换成圆弧就行,比如把步骤2和3改成画圆角,调整起来也很方便~

火山引擎 最新活动