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)
核心关键点:
from 90deg:渐变从顶部(90°方向)开始,而Flutter的SweepGradient默认从右侧(0°)开始,这是你之前渐变方向不对的核心原因。- 色标角度:所有角度都是绝对角度,需要转换成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, ), ), ], ), ), ); }
关键细节说明
- 角度对齐:用
startAngle: math.pi/2让渐变从顶部开始,完美匹配Figma的from 90deg。 - 色标精准度:所有
stops都是用Figma的角度除以360计算出来的,确保透明和白色的位置完全和设计一致。 - 毛玻璃效果:你的
BackdropFilter和ClipRRect的嵌套顺序是对的,这样能保证模糊效果只作用在容器范围内,不会溢出。
这样调整后,应该就能1:1还原Figma的设计了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

