Flutter TabBar自定义渐变边框+渐变背景Indicator实现求助
实现带渐变边框+渐变背景的TabBar自定义Indicator
由于Flutter的BoxDecoration无法直接实现渐变边框(Border.all仅支持纯色),你需要自定义一个Decoration来实现需求。以下是完整的可行方案:
1. 自定义渐变边框Indicator类
创建继承自Decoration的类,通过重写paint方法分别绘制渐变边框和渐变背景:
class GradientBorderIndicator extends Decoration { final double borderWidth; final BorderRadius borderRadius; final Gradient borderGradient; final Gradient backgroundGradient; const GradientBorderIndicator({ this.borderWidth = 2.0, this.borderRadius = const BorderRadius.all(Radius.circular(16)), required this.borderGradient, required this.backgroundGradient, }); @override BoxPainter createBoxPainter([VoidCallback? onChanged]) { return _GradientBorderPainter( borderWidth: borderWidth, borderRadius: borderRadius, borderGradient: borderGradient, backgroundGradient: backgroundGradient, ); } } class _GradientBorderPainter extends BoxPainter { final double borderWidth; final BorderRadius borderRadius; final Gradient borderGradient; final Gradient backgroundGradient; _GradientBorderPainter({ required this.borderWidth, required this.borderRadius, required this.borderGradient, required this.backgroundGradient, }); @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { final Rect rect = offset & configuration.size!; // 计算内部背景矩形(减去边框宽度) final Rect innerRect = rect.deflate(borderWidth); // 边框的圆角路径 final RRect borderRRect = borderRadius.toRRect(rect); // 内部背景的圆角路径(半径减去边框宽度) final RRect innerRRect = borderRadius.subtract(BorderRadius.circular(borderWidth)).toRRect(innerRect); // 绘制渐变边框 final Paint borderPaint = Paint() ..shader = borderGradient.createShader(rect) ..style = PaintingStyle.stroke ..strokeWidth = borderWidth; canvas.drawRRect(borderRRect, borderPaint); // 绘制渐变背景 final Paint backgroundPaint = Paint() ..shader = backgroundGradient.createShader(innerRect); canvas.drawRRect(innerRRect, backgroundPaint); } }
2. 在TabBar中使用自定义Indicator
修改原有代码,替换BoxDecoration为自定义的GradientBorderIndicator:
@override Widget build(BuildContext context) { List<String> list = ["全部","读书","电影", "小说"]; // 定义边框渐变和背景渐变 final borderGradient = LinearGradient( colors: [ Color(0xFF08FFFB), Color(0xFFFF4EEC), ], ); final backgroundGradient = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFF3A3A3A), Color(0xFF0B0B0B), ], ); return Padding( padding: EdgeInsets.fromLTRB(15, 0, 15, 0), child: Container( width: double.infinity, height: 62, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20)) ), child: Padding( padding: EdgeInsets.fromLTRB(25, 13, 25, 13), child: TabBar( labelColor: Colors.white, unselectedLabelColor: YYSColors.yysTextColor(), isScrollable: true, // 使用自定义Indicator indicator: GradientBorderIndicator( borderWidth: 2, borderRadius: BorderRadius.circular(16), borderGradient: borderGradient, backgroundGradient: backgroundGradient, ), tabs: list .map((String arenaType) { return Tab(text: arenaType); }).toList(), ), ), ), ); }
关键说明
- 自定义Indicator通过两次绘制实现:先画渐变边框(
PaintingStyle.stroke),再画内部渐变背景(默认PaintingStyle.fill)。 - 内部背景的圆角半径需减去边框宽度,避免背景超出边框导致圆角显示异常。
- 直接用
Color(0xFFxxxxxx)语法替代int.parse,代码更简洁高效。
内容的提问来源于stack exchange,提问作者Wilson Tang
相关产品推荐
相关产品推荐

