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

如何在Flutter中实现类似CSS的Squircle形状容器?

Flutter 实现 Squircle UI 容器方案

普通的 BorderRadius.circular 只能生成圆形圆角,无法实现 Squircle 那种包含边部平滑曲线的特殊形状,你可以通过以下几种原生方法实现需求:

方法1:椭圆圆角(简单快速,接近基础 Squircle)

使用 Radius.elliptical 为每个角设置不同的水平/垂直半径,模拟 Squircle 的椭圆边角效果,适合快速实现基础样式:

import 'package:flutter/material.dart';

class FrostedGlassBox extends StatelessWidget {
  const FrostedGlassBox({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300, // *根据需求设置宽高*
      height: 200,
      decoration: BoxDecoration(
        color: Colors.amber,
        // *水平半径44,垂直半径22,可根据需求调整*
        borderRadius: BorderRadius.all(Radius.elliptical(44, 22)),
      ),
    );
  }
}

方法2:自定义 ClipPath(完全自定义曲线)

通过 ClipPath 绘制完全符合需求的 Squircle 路径,适合需要边部也有弧度的场景:

首先定义自定义 Clipper:

class SquircleClipper extends CustomClipper<Path> {
  final double curveRadius;

  SquircleClipper(this.curveRadius);

  @override
  Path getClip(Size size) {
    final path = Path();
    final centerX = size.width / 2;
    final centerY = size.height / 2;

    // 用三次贝塞尔曲线绘制四边平滑曲线
    path.moveTo(centerX, 0);
    path.cubicTo(
      size.width - curveRadius, 0,
      size.width, curveRadius,
      size.width, centerY,
    );
    path.cubicTo(
      size.width, size.height - curveRadius,
      size.width - curveRadius, size.height,
      centerX, size.height,
    );
    path.cubicTo(
      curveRadius, size.height,
      0, size.height - curveRadius,
      0, centerY,
    );
    path.cubicTo(
      0, curveRadius,
      curveRadius, 0,
      centerX, 0,
    );
    path.close();
    return path;
  }

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

然后在组件中使用:

class FrostedGlassBox extends StatelessWidget {
  const FrostedGlassBox({super.key});

  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: SquircleClipper(22), // *调整曲线弧度*
      child: Container(
        width: 300,
        height: 200,
        color: Colors.amber,
      ),
    );
  }
}

方法3:自定义 ShapeBorder(集成到 BoxDecoration)

自定义 ShapeBorder,可以直接在 BoxDecoration 的 shape 属性中使用,无需额外的 Clip 组件:

首先定义自定义 Border:

class SquircleBorder extends ShapeBorder {
  final double curveRadius;

  SquircleBorder(this.curveRadius);

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) => getOuterPath(rect);

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    final centerX = rect.center.dx;
    final centerY = rect.center.dy;
    final path = Path();

    path.moveTo(centerX, rect.top);
    path.cubicTo(
      rect.right - curveRadius, rect.top,
      rect.right, rect.top + curveRadius,
      rect.right, centerY,
    );
    path.cubicTo(
      rect.right, rect.bottom - curveRadius,
      rect.right - curveRadius, rect.bottom,
      centerX, rect.bottom,
    );
    path.cubicTo(
      rect.left + curveRadius, rect.bottom,
      rect.left, rect.bottom - curveRadius,
      rect.left, centerY,
    );
    path.cubicTo(
      rect.left, rect.top + curveRadius,
      rect.left + curveRadius, rect.top,
      centerX, rect.top,
    );
    path.close();
    return path;
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}

  @override
  ShapeBorder scale(double t) => SquircleBorder(curveRadius * t);
}

然后在组件中使用:

class FrostedGlassBox extends StatelessWidget {
  const FrostedGlassBox({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 200,
      decoration: BoxDecoration(
        color: Colors.amber,
        shape: SquircleBorder(22), // *调整曲线弧度*
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Satyam Mishra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:25:13