import 'package:flutter/material.dart'; class GradientLayer { final Gradient gradient; final BlendMode blendMode; const GradientLayer({ required this.gradient, this.blendMode = BlendMode.srcIn, // 默认第一层用 srcIn 打底 }); } class GradientText extends StatelessWidget { final String data; final TextStyle? style; final TextAlign? textAlign; final TextDirection? textDirection; final bool softWrap; final TextOverflow? overflow; final double? textScaleFactor; final int? maxLines; final Locale? locale; final String? semanticsLabel; final TextWidthBasis? textWidthBasis; final TextHeightBehavior? textHeightBehavior; final List gradientLayers; const GradientText({ Key? key, required this.data, this.style, this.textAlign, this.textDirection, this.softWrap = true, this.overflow, this.textScaleFactor, this.maxLines, this.locale, this.semanticsLabel, this.textWidthBasis, this.textHeightBehavior, this.gradientLayers = const [], }) : super(key: key); @override Widget build(BuildContext context) { if (gradientLayers.isEmpty) { return Text( data, style: style, textAlign: textAlign, textDirection: textDirection, softWrap: softWrap, overflow: overflow, textScaleFactor: textScaleFactor, maxLines: maxLines, locale: locale, semanticsLabel: semanticsLabel, textWidthBasis: textWidthBasis, textHeightBehavior: textHeightBehavior, ); } final baseStyle = style ?? const TextStyle(); return Stack( children: [ // 1. 最底层:纯色文本(可选,防止所有渐变都透明时看不见) // 如果第一层渐变是 srcIn,这一层其实可以被遮挡,但保留它作为“备用底色” Opacity( opacity: 0.0, // 隐藏,仅占位 child: _buildText(baseStyle.copyWith(color: Colors.black)), ), // 2. 叠加渐变层 ...gradientLayers.asMap().entries.map((entry) { final index = entry.key; final layer = entry.value; // 关键逻辑: // 如果是第一层且用户没改 blendMode,默认用 srcIn 确保文字有颜色 // 如果是后续层,通常希望融合,所以建议用户传入 overlay/plus 等 return ShaderMask( shaderCallback: (Rect bounds) { return layer.gradient.createShader(bounds); }, blendMode: layer.blendMode, child: _buildText( // 重要:为了融合效果,内部文本通常是白色或浅色 // 如果 blendMode 是 srcIn,颜色不重要(会被渐变替换) // 如果 blendMode 是 overlay/plus,白色能让渐变颜色最纯正地显示 baseStyle.copyWith(color: Colors.white), ), ); }).toList(), ], ); } Widget _buildText(TextStyle effectiveStyle) { return Text( data, style: effectiveStyle, textAlign: textAlign, textDirection: textDirection, softWrap: softWrap, overflow: overflow, textScaleFactor: textScaleFactor, maxLines: maxLines, locale: locale, semanticsLabel: semanticsLabel, textWidthBasis: textWidthBasis, textHeightBehavior: textHeightBehavior, ); } }