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

如何在Flutter中创建自定义形状控件以实现菜单页异形菜单项

Flutter 自定义形状菜单项实现方案

核心实现逻辑是通过 Flutter 自带的 ShapeBorder 、CustomClipper<Path> 绘制能力配合可点击组件实现异形菜单项,不需要引入第三方依赖,各分类对应实现方式如下:

  • 美食分类(圆形):直接通过 BoxDecoration 自带的圆形属性实现
  • 饮品、促销活动分类(圆角矩形):通过 BoxDecoration 的圆角属性实现
  • 甜点分类(圆角变形三角形):自定义 CustomClipper 绘制带圆角的轻微变形三角形

各分类代码示例

1. 美食分类圆形菜单项

InkWell(
  onTap: () {
    // 处理美食分类点击逻辑
  },
  child: Container(
    width: 80,
    height: 80,
    decoration: const BoxDecoration(
      color: Colors.orange,
      shape: BoxShape.circle,
    ),
    child: const Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(Icons.restaurant, color: Colors.white, size: 32),
        Text("美食", style: TextStyle(color: Colors.white, fontSize: 12))
      ],
    ),
  ),
)

2. 饮品/促销活动圆角矩形菜单项

InkWell(
  onTap: () {
    // 处理对应分类点击逻辑
  },
  child: Container(
    width: 140,
    height: 60,
    decoration: BoxDecoration(
      // 促销活动可更换为对应的主题色
      color: Colors.blue,
      borderRadius: BorderRadius.circular(16),
    ),
    child: const Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(Icons.local_drink, color: Colors.white),
        SizedBox(width: 6),
        Text("饮品", style: TextStyle(color: Colors.white))
      ],
    ),
  ),
)

3. 甜点分类圆角变形三角形菜单项

首先自定义三角形裁剪器:

class RoundedDeformTriangleClipper extends CustomClipper<Path> {
  final double radius;
  // 调整该参数控制三角形变形程度,1为正三角形,小于1底部边缩短
  final double deformRate;

  RoundedDeformTriangleClipper({
    this.radius = 10,
    this.deformRate = 0.85,
  });

  @override
  Path getClip(Size size) {
    Path path = Path();
    // 三个顶点坐标,按变形率调整底部边长度
    Offset topPoint = Offset(size.width / 2, 0);
    Offset bottomLeft = Offset(size.width * (1 - deformRate) / 2, size.height - radius);
    Offset bottomRight = Offset(size.width * (1 + deformRate) / 2, size.height - radius);

    // 绘制带圆角的三条边
    path.moveTo(topPoint.dx, topPoint.dy + radius);
    path.arcToPoint(Offset(topPoint.dx + radius, topPoint.dy), radius: Radius.circular(radius));
    path.lineTo(bottomRight.dx - radius * 0.6, bottomRight.dy - radius * 0.6);
    path.arcToPoint(Offset(bottomRight.dx, bottomRight.dy + radius), radius: Radius.circular(radius));
    path.lineTo(bottomLeft.dx, bottomLeft.dy + radius);
    path.arcToPoint(Offset(bottomLeft.dx - radius, bottomLeft.dy), radius: Radius.circular(radius));
    path.lineTo(topPoint.dx - radius, topPoint.dy + radius);
    path.arcToPoint(Offset(topPoint.dx, topPoint.dy + radius), radius: Radius.circular(radius));
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

使用裁剪器实现菜单项:

InkWell(
  onTap: () {
    // 处理甜点分类点击逻辑
  },
  child: ClipPath(
    clipper: RoundedDeformTriangleClipper(deformRate: 0.85, radius: 10),
    child: Container(
      width: 90,
      height: 90,
      color: Colors.pinkAccent,
      child: const Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.cake, color: Colors.white, size: 30),
          Text("甜点", style: TextStyle(color: Colors.white, fontSize: 12))
        ],
      ),
    ),
  ),
)

页面布局建议

所有菜单项可使用 Wrap 或者 GridView 组件排列,根据实际设计稿调整组件尺寸、间距即可。如果需要点击水波纹效果,确保 InkWell 的父级包含 Material 组件即可。

设计参考图:菜单设计参考图

内容的提问来源于stack exchange,提问作者Muhammad Ibrahim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 19:30:01