ChatGPT解决这个技术问题 Extra ChatGPT

How to add shadow to the text in flutter?

I searched for the shadow option in TextStyle, but I didn't find it. So I ask: how can I add shadow to the text in flutter? Is it possible? Example:

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

G
Gary Qian

Text shadows are now a property of TextStyle as of this commit

To enable text shadows, please make sure you are on an up-to-date version of Flutter ($ flutter upgrade) and provide a List<Shadow> to 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),
      ),
    ],
  ),
),

...

Keep in mind that shadows will be drawn in the order provided.


I did a flutter ugprade command but cant see the 'shadows' property. Flutter 0.9.4 • channel beta.
You will likely have to wait for the next weekly beta release. This change just landed and will take a few weeks to make it to the beta channel. You can try a different channel such as dev, which is on a much more rapid release schedule, where the feature should be available within a few hours up to a few days.
FYI - as of today this is only available on Flutter master, but it will eventually make its way through.
How can I use this with icons ?
@TSR Here is an example using it with icons: gist.github.com/mateusfccp/1f6f310295a429372780f5e04468524c I also opened an issue and PR to export the shadows parameter to Icon: github.com/flutter/flutter/issues/83637
D
Dan Field

Flutter now provides a way to do this without any work-arounds, as documented in issue 3402 and Gary Qian's answer below.

While this makes its way into the more stable channels, it's possible to fake a shadow using BackdropFilter.

https://i.stack.imgur.com/r8ySD.png

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,
          ),
        ),
      ),
    );
  }
}

Or if you don't care about the blur, just make a Stack with a few some semitransparent Text widgets stacked not quite precisely on top of each other.

Like this:

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,
          ),
        ],
      ),
    );
  }
}

Take care with this code and use the profiler to ensure proper performance. It works fine, but I wanted to put blurred shadows in a lot of places and because it is GPU expensive I was slowing down the app. Finally I kept the shadow but I removed the blur as it also shown in this answers. Thanks Collin!
@Collin Collin - Kindly update the answer as per NULL SAFETY. Thanks a lot.
It creates a square/rectangle blurred box then put the text in it. Which is not good solution, We need solution to set shadow to the text, not change the background color to highlight text. Is there any suggestion or solution? Please share. thanks.
S
Suragch

Here is a little playing around with the opacity, offset, and shadow radius:

https://i.stack.imgur.com/CcaLp.gif

The full code is here. Try it out yourself.

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)},
                ),
              ],
            ),
          ),
        )
      ],
    );
  }
}

I created it on dartpad and printing various axis values as well: dartpad.dev/a27701b1699f3c44cfc9aef91b9ba214
R
Rody Davis

Expanding on Collin Jackson's answer. This will account for the various TextAlign properties.

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,
          ),
        ],
      ),
    );
  }
}

Then whenever you want to use this just import this file at the top and replace the Text() with ShadowText() widget.