如何在Flutter中实现如图所示的文本样式及内部阴影效果?

Flutter 文本添加内部阴影的解决方案
下面是几种可行的实现方案,你可以根据需求选择:
方法一:使用ShaderMask组件
这是最简洁的实现方式,通过渐变着色器配合混合模式,只在文本区域内生成阴影效果。
ShaderMask( shaderCallback: (bounds) => RadialGradient( center: Alignment.center, radius: 1.0, colors: [Colors.black.withOpacity(0.6), Colors.transparent], stops: const [0.5, 1.0], ).createShader(bounds), blendMode: BlendMode.dstIn, child: const Text( "INNER SHADOW", style: TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: Colors.white, ), ), )
原理:径向渐变从文本中心的半透明黑色过渡到透明,BlendMode.dstIn让渐变仅作用于文本的像素区域,模拟出内部阴影的视觉效果。你可以调整渐变的参数(比如方向、颜色、停止点)来改变阴影的样式。
方法二:自定义CustomPaint绘制
如果需要更精细控制阴影的偏移、模糊程度等,可以用自定义绘制实现:
CustomPaint( painter: _InnerShadowTextPainter( text: "INNER SHADOW", textStyle: const TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: Colors.white, ), shadowColor: Colors.black.withOpacity(0.5), shadowOffset: const Offset(2, 2), ), size: const Size(double.infinity, 100), )
对应的自定义Painter类:
class _InnerShadowTextPainter extends CustomPainter { final String text; final TextStyle textStyle; final Color shadowColor; final Offset shadowOffset; _InnerShadowTextPainter({ required this.text, required this.textStyle, required this.shadowColor, required this.shadowOffset, }); @override void paint(Canvas canvas, Size size) { // 先绘制偏移的阴影文本 final shadowSpan = TextSpan(text: text, style: textStyle.copyWith(color: shadowColor)); final shadowPainter = TextPainter( text: shadowSpan, textAlign: TextAlign.center, textDirection: TextDirection.ltr, )..layout(minWidth: size.width, maxWidth: size.width); shadowPainter.paint(canvas, shadowOffset); // 裁剪出原文本的区域,只保留该区域内的内容 final textPath = shadowPainter.getBounds().toPath(); canvas.save(); canvas.clipPath(textPath); // 绘制原文本,覆盖阴影,仅保留文本内部的阴影部分 final originalSpan = TextSpan(text: text, style: textStyle); final originalPainter = TextPainter( text: originalSpan, textAlign: TextAlign.center, textDirection: TextDirection.ltr, )..layout(minWidth: size.width, maxWidth: size.width); originalPainter.paint(canvas, Offset.zero); canvas.restore(); } @override bool shouldRepaint(covariant _InnerShadowTextPainter oldDelegate) { return text != oldDelegate.text || textStyle != oldDelegate.textStyle || shadowColor != oldDelegate.shadowColor || shadowOffset != oldDelegate.shadowOffset; } }
方法三:Stack+ClipPath组合
通过层叠文本和裁剪的方式实现内部阴影:
Stack( alignment: Alignment.center, children: [ // 底层的阴影文本 const Text( "INNER SHADOW", style: TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: Colors.black38, ), ), // 用原文本的形状裁剪,只保留阴影在文本内部的部分 ClipPath( clipper: _TextClipper( text: "INNER SHADOW", textStyle: const TextStyle( fontSize: 48, fontWeight: FontWeight.bold, ), ), child: const Text( "INNER SHADOW", style: TextStyle( fontSize: 48, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ], )
对应的自定义裁剪器:
class _TextClipper extends CustomClipper<Path> { final String text; final TextStyle textStyle; _TextClipper({required this.text, required this.textStyle}); @override Path getClip(Size size) { final textPainter = TextPainter( text: TextSpan(text: text, style: textStyle), textAlign: TextAlign.center, textDirection: TextDirection.ltr, )..layout(minWidth: size.width, maxWidth: size.width); return textPainter.getBounds().toPath(); } @override bool shouldReclip(covariant _TextClipper oldClipper) { return text != oldClipper.text || textStyle != oldClipper.textStyle; } }
内容的提问来源于stack exchange,提问作者Ahmed Iqbal teli
相关产品推荐
相关产品推荐

