【问题标题】:How to add shadow to the text in flutter?如何在颤动中为文本添加阴影?
【发布时间】:2026-01-29 23:05:01
【问题描述】:

我在 TextStyle 中搜索了阴影选项,但没有找到。所以我问:如何在颤动中为文本添加阴影?可能吗? 示例:

new Text(
"asd"
style: new TextStyle( 
//add shadow?
));

【问题讨论】:

    标签: flutter dart text shadow


    【解决方案1】:

    Flutter 现在提供了一种无需任何变通方法即可做到这一点的方法,如 issue 3402Gary Qian's answer below 中所述。

    虽然这会进入更稳定的通道,但可以使用 BackdropFilter 伪造阴影。

    import 'dart:ui' as ui;
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(new MaterialApp(
        home: new MyApp(),
      ));
    }
    
    class ShadowText extends StatelessWidget {
      ShadowText(this.data, { this.style }) : assert(data != null);
    
      final String data;
      final TextStyle style;
    
      Widget build(BuildContext context) {
        return new ClipRect(
          child: new Stack(
            children: [
              new Positioned(
                top: 2.0,
                left: 2.0,
                child: new Text(
                  data,
                  style: style.copyWith(color: Colors.black.withOpacity(0.5)),
                ),
              ),
              new BackdropFilter(
                filter: new ui.ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0),
                child: new Text(data, style: style),
              ),
            ],
          ),
        );
      }
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: new Container(
            child: new Center(
              child: new ShadowText(
                'Hello world!',
                style: Theme.of(context).textTheme.display3,
              ),
            ),
          ),
        );
      }
    }
    

    或者,如果您不关心模糊,只需制作一个 Stack 和一些半透明的 Text 小部件,这些小部件并不完全堆叠在一起。

    像这样:

    import 'package:flutter/material.dart';
    
    class ShadowText 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;
    
      const ShadowText(this.data, {
        Key key,
        this.style,
        this.textAlign,
        this.textDirection,
        this.softWrap,
        this.overflow,
        this.textScaleFactor,
        this.maxLines,
      }) : assert(data != null);
    
      Widget build(BuildContext context) {
        return new ClipRect(
          child: new Stack(
            children: [
              new Positioned(
                top: 2.0,
                left: 2.0,
                child: new Text(
                  data,
                  style: style.copyWith(color: Colors.black.withOpacity(0.5)),
                  textAlign: textAlign,
                  textDirection: textDirection,
                  softWrap: softWrap,
                  overflow: overflow,
                  textScaleFactor: textScaleFactor,
                  maxLines: maxLines,
                ),
              ),
              new Text(
                data,
                style: style,
                textAlign: textAlign,
                textDirection: textDirection,
                softWrap: softWrap,
                overflow: overflow,
                textScaleFactor: textScaleFactor,
                maxLines: maxLines,
              ),
            ],
          ),
        );
      }
    }
    

    【讨论】:

    • 注意这段代码并使用分析器来确保正确的性能。它工作得很好,但我想在很多地方放置模糊的阴影,而且因为它的 GPU 昂贵,所以我减慢了应用程序的速度。最后我保留了阴影,但我删除了模糊,因为它也显示在这个答案中。谢谢科林!
    • @Collin Collin - 请根据 NULL SAFETY 更新答案。非常感谢。
    • 它创建一个方形/矩形模糊框,然后将文本放入其中。这不是一个好的解决方案,我们需要为文本设置阴影的解决方案,而不是更改背景颜色以突出显示文本。有什么建议或解决方案吗?请分享。谢谢。
    【解决方案2】:

    扩展科林杰克逊的答案。这将解释各种 TextAlign 属性。

    import 'package:flutter/material.dart';
    
    class ShadowText 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;
    
      const ShadowText(
        this.data, {
        Key key,
        this.style,
        this.textAlign,
        this.textDirection,
        this.softWrap,
        this.overflow,
        this.textScaleFactor,
        this.maxLines,
      }) : assert(data != null);
    
      Widget build(BuildContext context) {
        AlignmentDirectional _align;
        switch (textAlign) {
          case TextAlign.justify:
          case TextAlign.center:
            _align = AlignmentDirectional.center;
            break;
          case TextAlign.end:
          case TextAlign.right:
            _align = AlignmentDirectional.centerEnd;
            break;
          case TextAlign.start:
          case TextAlign.left:
            _align = AlignmentDirectional.centerStart;
            break;
          default:
            _align = AlignmentDirectional.center;
        }
        return new ClipRect(
          child: new Stack(
            alignment: _align,
            children: [
              Text(data,
                  style: style.copyWith(color: Colors.black.withOpacity(0.5)),
                  textAlign: textAlign,
                  textDirection: textDirection,
                  softWrap: softWrap,
                  overflow: overflow,
                  textScaleFactor: textScaleFactor + 0.03,
                  maxLines: maxLines),
              new Text(
                data,
                style: style,
                textAlign: textAlign,
                textDirection: textDirection,
                softWrap: softWrap,
                overflow: overflow,
                textScaleFactor: textScaleFactor,
                maxLines: maxLines,
              ),
            ],
          ),
        );
      }
    }
    

    然后,只要您想使用它,只需在顶部导入此文件并将Text() 替换为ShadowText() 小部件。

    【讨论】:

      【解决方案3】:

      this commit 开始,文本阴影现在是TextStyle 的属性

      要启用文本阴影,请确保您使用的是最新版本的 Flutter ($ flutter upgrade) 并提供 List<Shadow>TextStyle.shadows

      import 'dart:ui';
      
      ...
      
      Text(
        'Hello, world!',
        style: TextStyle(
          shadows: <Shadow>[
            Shadow(
              offset: Offset(10.0, 10.0),
              blurRadius: 3.0,
              color: Color.fromARGB(255, 0, 0, 0),
            ),
            Shadow(
              offset: Offset(10.0, 10.0),
              blurRadius: 8.0,
              color: Color.fromARGB(125, 0, 0, 255),
            ),
          ],
        ),
      ),
      
      ...
      

      请记住,阴影将按照提供的顺序绘制。

      【讨论】:

      • 我做了一个颤振的 ugprade 命令,但看不到“阴影”属性。 Flutter 0.9.4 • 频道测试版。
      • 您可能需要等待下一个每周测试版发布。此更改刚刚落地,需要几周时间才能进入测试版通道。您可以尝试其他渠道,例如 dev,它的发布计划要快得多,该功能应该会在几小时到几天内推出。
      • 仅供参考 - 到目前为止,这仅在 Flutter master 上可用,但最终会通过。
      • 如何将它与图标一起使用?
      • @TSR 这是一个使用图标的示例:gist.github.com/mateusfccp/1f6f310295a429372780f5e04468524c 我还打开了一个问题和 PR 以将 shadows 参数导出到 Icongithub.com/flutter/flutter/issues/83637
      【解决方案4】:

      这里是关于不透明度、偏移量和阴影半径的小玩意:

      完整的代码在这里。自己试试吧。

      import 'package:flutter/material.dart';
      
      void main() => runApp(MyApp());
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: Scaffold(
              body: ShadowDemo(),
            ),
          );
        }
      }
      
      class ShadowDemo extends StatefulWidget {
        @override
        _ShadowDemoState createState() => _ShadowDemoState();
      }
      
      class _ShadowDemoState extends State<ShadowDemo> {
        var _opacity = 1.0;
        var _xOffset = 0.0;
        var _yOffset = 0.0;
        var _blurRadius = 0.0;
      
        @override
        Widget build(BuildContext context) {
          return Stack(
            children: <Widget>[
              Center(
                  child: Text(
                'Flutter',
                style: TextStyle(
                  fontSize: 100,
                  color: Colors.blue.shade700,
                  shadows: [
                    Shadow(
                      color: Colors.blue.shade900.withOpacity(_opacity),
                      offset: Offset(_xOffset, _yOffset),
                      blurRadius: _blurRadius,
                    ),
                  ],
                ),
              )),
              Align(
                alignment: Alignment.bottomCenter,
                child: Padding(
                  padding: const EdgeInsets.only(bottom: 80.0),
                  child: Column(
                    children: <Widget>[
                      Spacer(),
                      Slider(
                        value: _opacity,
                        min: 0.0,
                        max: 1.0,
                        onChanged: (newValue) =>
                            {setState(() => _opacity = newValue)},
                      ),
                      Slider(
                        value: _xOffset,
                        min: -100,
                        max: 100,
                        onChanged: (newValue) =>
                            {setState(() => _xOffset = newValue)},
                      ),
                      Slider(
                        value: _yOffset,
                        min: -100,
                        max: 100,
                        onChanged: (newValue) =>
                            {setState(() => _yOffset = newValue)},
                      ),
                      Slider(
                        value: _blurRadius,
                        min: 0,
                        max: 100,
                        onChanged: (newValue) =>
                            {setState(() => _blurRadius = newValue)},
                      ),
                    ],
                  ),
                ),
              )
            ],
          );
        }
      }
      

      【讨论】:

      【解决方案5】:

      为了更清晰,您可以使用flutter_shine

      Flutter Shine 是一个用于漂亮阴影、动态灯光位置、高度可定制的阴影、无库依赖、基于内容的文本或框阴影的库。

      添加包

      dependencies:
        flutter_shine: ^0.0.5
      

      在文本和容器上创建阴影很容易。

      FlutterShine(
          builder: (BuildContext context, ShineShadow shineShadow) {
              return Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                      Text(
                          "Shine",
                          style: TextStyle(
                              fontSize: 100,
                              color: Colors.white,
                              shadows: shineShadow.shadows),
                      ),
                      Divider(),
                      Container(
                          width: 300,
                          height: 300,
                          decoration: BoxDecoration(
                              color: Colors.white, boxShadow: shineShadow.boxShadows),
                      )
                  ],
              );
          },
      ),
      

      【讨论】: