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

Flutter中如何精准复刻Figma指定的锥形渐变边框毛玻璃容器?

Flutter中如何精准复刻Figma指定的锥形渐变边框毛玻璃容器?

我太懂这种Figma转Flutter的痛点了——尤其是锥形渐变这种原生支持不够友好的效果,参数稍微错一点就和设计差得远。你现在的问题主要出在SweepGradient的角度和色标没有和Figma的参数精准对齐,还有第三方渐变边框包的适配问题,我来一步步帮你修正:

先拆解Figma的渐变参数

Figma给的锥形渐变是:

conic-gradient(from 90deg at 50% 50%, rgba(255,255,255,0) -37.26deg, #FFFFFF 50.99deg, rgba(255,255,255,0) 143.54deg, #FFFFFF 235.25deg, rgba(255,255,255,0) 322.74deg, #FFFFFF 410.99deg)

核心关键点:

  1. from 90deg:渐变从顶部(90°方向)开始,而Flutter的SweepGradient默认从右侧(0°)开始,这是你之前渐变方向不对的核心原因。
  2. 色标角度:所有角度都是绝对角度,需要转换成0-360°的比例,再映射到SweepGradient的stops(0-1范围)。

修正后的实现方案

我给你两种实现方式,第一种是调整你原有的第三方包代码,第二种是用原生CustomPaint绘制(更稳定,避免第三方包的适配问题)。

方式1:调整原有的GradientBoxBorder参数

直接替换你代码中SweepGradient的部分,完全对齐Figma的参数:

gradient: SweepGradient(
  center: Alignment.center,
  startAngle: math.pi / 2, // 对应Figma的from 90deg(90°=π/2弧度)
  endAngle: math.pi / 2 + 2 * math.pi, // 从顶部开始完整旋转一圈
  tileMode: TileMode.clamp,
  colors: const [
    Colors.white,
    Colors.transparent,
    Colors.white,
    Colors.transparent,
    Colors.white,
    Colors.transparent,
  ],
  stops: const [
    0.0,
    0.1416, // 50.99°/360°≈0.1416
    0.3987, // 143.54°/360°≈0.3987
    0.6535, // 235.25°/360°≈0.6535
    0.8965, // 322.74°/360°≈0.8965
    1.0,
  ],
),

这里已经把Figma的所有色标角度转换成了stops,同时用startAngle对齐了渐变的起始方向。

方式2:用原生CustomPaint绘制边框(更稳定)

如果你发现第三方包的GradientBoxBorder对SweepGradient的支持有偏差,可以用原生绘制来精准控制:

首先定义一个绘制锥形渐变边框的Painter:

class ConicBorderPainter extends CustomPainter {
  final double borderRadius;
  final double borderWidth;
  final SweepGradient gradient;

  ConicBorderPainter({
    required this.borderRadius,
    required this.borderWidth,
    required this.gradient,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Rect.fromLTWH(0, 0, size.width, size.height);
    final roundedRect = RRect.fromRectAndRadius(rect, Radius.circular(borderRadius));
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = borderWidth
      ..shader = gradient.createShader(rect);
    canvas.drawRRect(roundedRect, paint);
  }

  @override
  bool shouldRepaint(ConicBorderPainter oldDelegate) {
    return oldDelegate.borderRadius != borderRadius ||
        oldDelegate.borderWidth != borderWidth ||
        oldDelegate.gradient != gradient;
  }
}

然后修改你的FrostedConicBox的build方法:

@override
Widget build(BuildContext context) {
  final boxWidth = ResponsiveHelper.wp(context, 176);
  final boxHeight = ResponsiveHelper.hp(context, 65);
  final conicGradient = SweepGradient(
    center: Alignment.center,
    startAngle: math.pi / 2,
    endAngle: math.pi / 2 + 2 * math.pi,
    tileMode: TileMode.clamp,
    colors: const [
      Colors.white,
      Colors.transparent,
      Colors.white,
      Colors.transparent,
      Colors.white,
      Colors.transparent,
    ],
    stops: const [
      0.0,
      0.1416,
      0.3987,
      0.6535,
      0.8965,
      1.0,
    ],
  );

  return ClipRRect(
    borderRadius: BorderRadius.circular(16),
    child: BackdropFilter(
      filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
      child: Stack(
        children: [
          // 毛玻璃容器本体
          Container(
            width: boxWidth,
            height: boxHeight,
            padding: const EdgeInsets.symmetric(horizontal: 12),
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.1),
              borderRadius: BorderRadius.circular(16),
            ),
            child: Row(
              children: [
                ClipRRect(
                  borderRadius: BorderRadius.circular(8),
                  child: Image.asset(
                    imagePath,
                    width: 45,
                    height: 45,
                    fit: BoxFit.cover,
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: Text(
                    label,
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w600,
                      fontSize: 15,
                    ),
                    overflow: TextOverflow.ellipsis,
                  ),
                ),
              ],
            ),
          ),
          // 锥形渐变边框
          CustomPaint(
            size: Size(boxWidth, boxHeight),
            painter: ConicBorderPainter(
              borderRadius: 16,
              borderWidth: 1,
              gradient: conicGradient,
            ),
          ),
        ],
      ),
    ),
  );
}

关键细节说明

  1. 角度对齐:用startAngle: math.pi/2让渐变从顶部开始,完美匹配Figma的from 90deg。
  2. 色标精准度:所有stops都是用Figma的角度除以360计算出来的,确保透明和白色的位置完全和设计一致。
  3. 毛玻璃效果:你的BackdropFilter和ClipRRect的嵌套顺序是对的,这样能保证模糊效果只作用在容器范围内,不会溢出。

这样调整后,应该就能1:1还原Figma的设计了!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:24:30