制作 BoxDecoration 图片 faded/transparent

Make BoxDecoration image faded/transparent

我有以下代码片段,我想让图像褪色,这样它就不会干扰容器中的其他项目。 是否有可以实现此目的的过滤器?

child: new Card(
  child: new Container(
    decoration: new BoxDecoration(
      color: const Color(0xff7c94b6),
        image: new DecorationImage(
          image: new ExactAssetImage('lib/images/pic1.jpg'),
             )
           )
     )
   )

你可以给你的 DecorationImage 一个 ColorFilter 使背景图像变成灰色(使用 saturation 滤色器)或半透明(使用 dstATop 滤色器).

此示例的代码如下。

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) => new Scaffold(
    appBar: new AppBar(
      title: new Text('Grey Example'),
    ),
    body: new Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        new Card(
          child: new Container(
            child: new Text(
              'Hello world',
              style: Theme.of(context).textTheme.display4
            ),
            decoration: new BoxDecoration(
              color: const Color(0xff7c94b6),
              image: new DecorationImage(
                fit: BoxFit.cover,
                colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.2), BlendMode.dstATop),
                image: new NetworkImage(
                  'http://www.allwhitebackground.com/images/2/2582-190x190.jpg',
                ),
              ),
            ),
          ),
        ),
      ],
    ),
  );
}

Opacity 小部件是另一种选择。

您也可以预先将效果应用到资产。

您可以简单地使用 Stack 小部件,并在图像上方使用一个简单的彩色容器,降低不透明度。

EG :

        import 'package:flutter/material.dart';
        import 'package:flutter/widgets.dart';
        import 'package:flutter/rendering.dart';

        import './page2.dart';
        import './page3.dart';
        import './page4.dart';

        void main() {
          debugPaintSizeEnabled = true ;
          return runApp(Start());
        }

        class Start extends StatelessWidget {

          @override
          Widget build(BuildContext context) {
            // TODO: implement build
            return MaterialApp(
              title: 'InIt',
              home: Builder(builder: (context) {
                return GestureDetector(
                  onTap: () {
                    return Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (BuildContext context) {
                          return Page2();
                        },
                      ),
                    );
                  },
                  child: Scaffold(
                    body: Stack(
                      children: <Widget>[

                        Container(
                          decoration: BoxDecoration(
                            image: DecorationImage(
                                image: AssetImage('images/page1.jpg'),
                                fit: BoxFit.fitHeight),
                          ),
                        ),
                        Container(
                          color: Color.fromRGBO(255, 255, 255, 0.19),
                        ),
                        Container(
                          alignment: Alignment.center,
                          child: Center(
                            child: Text(
                              'LETS BE PRODUCTIVE TODAY',
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  fontSize: 50.0,
                                  fontFamily: 'bold',
                                  fontWeight: FontWeight.bold,
                                  color: Color.fromRGBO(255, 255, 255, 1)),
                            ),
                          ),
                        ),
                        Container(
                          margin: EdgeInsets.only(bottom: 10.0),
                          alignment: Alignment.bottomCenter,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              RawMaterialButton(
                                onPressed: () {},
                                constraints:
                                    BoxConstraints.tightFor(height: 10.0, width: 10.0),
                                shape: CircleBorder(),
                                fillColor: Colors.white,
                              ),
                              Page2call(),
                              Page3call(),
                              Page4call(),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                );
              }),
            );
          }
        }

        class Page2call extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            // TODO: implement build
            return RawMaterialButton(
              onPressed: () {
                return Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (BuildContext context) {
                      return Page2();
                    },
                  ),
                );
              },
              constraints: BoxConstraints.tightFor(height: 10.0, width: 10.0),
              shape: CircleBorder(),
              fillColor: Colors.white,
            );
          }
        }

        class Page3call extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            // TODO: implement build
            return RawMaterialButton(
              onPressed: () {
                return Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (BuildContext context) {
                      return Page3();
                    },
                  ),
                );
              },
              constraints: BoxConstraints.tightFor(height: 10.0, width: 10.0),
              shape: CircleBorder(),
              fillColor: Colors.white,
            );
          }
        }

        class Page4call extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            // TODO: implement build
            return RawMaterialButton(
              onPressed: () {
                return Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (BuildContext context) {
                      return Page4();
                    },
                  ),
                );
              },
              constraints: BoxConstraints.tightFor(height: 10.0, width: 10.0),
              shape: CircleBorder(),
              fillColor: Colors.white,
            );
          }
        }

这是一个完全实用的例子。你可以在这里增加不透明度 为了使背景更加褪色,第四个参数用于不透明度:

Container(
                color: Color.fromRGBO(255, 255, 255, 0.19),
         ),

此方法还使您能够选择褪色滤镜的颜色。

您可以简单地使用

ColorFiltered(
  colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.2), BlendMode.dstATop),
  child: YourWidget(),
) 

对于那些想知道 性能 是否正常的人(因为图像和不透明度都是 resource-heavy 的东西) ,这是我对文档、源代码和答案的深入研究。

结论:使用DecorationImage(colorFilter: ...)与官方文档建议的一样快。 (但是 OpacityColorFilter 小部件不是)

首先,我们应该使用OpacityColorFilter小部件,因为它可能触发saveLayer并且很昂贵(official doc).

相反,我们 should

Use the Opacity widget only when necessary. See the Transparent image section in the Opacity API page for an example of applying opacity directly to an image, which is faster than using the Opacity widget.

查看建议的 method,我们看到以下示例:

Image.network(
  'https://raw.githubusercontent.com/flutter/assets-for-api-docs/master/packages/diagrams/assets/blend_mode_destination.jpeg',
  color: Color.fromRGBO(255, 255, 255, 0.5),
  colorBlendMode: BlendMode.modulate
)

现在的问题是,highly-voted 答案,即下面的代码,是否与官方文档提到的 Image 小部件一样快?

Container(
  child: Text('hi'),
  decoration: BoxDecoration(
    color: const Color(0xff7c94b6),
    image: new DecorationImage(
      fit: BoxFit.cover,
      colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.2), BlendMode.dstATop),
      image: new NetworkImage(
        'http://www.allwhitebackground.com/images/2/2582-190x190.jpg',
      ),
    ),
  ),
),

要回答这个问题,让我们看看 Image.network 的来源。这个构造函数会直接填充Image.

colorBlendMode字段

Imagebuild中,会直接传递给RawImagecolorBlendMode字段。

然后,RawImage 将创建 RenderImage(这是一个 RenderObject)并更新 RenderImage._colorBlendMode

接下来,注意 RenderImage 如何处理这个 -

  BlendMode? _colorBlendMode;
  set colorBlendMode(BlendMode? value) {
    if (value == _colorBlendMode)
      return;
    _colorBlendMode = value;
    _updateColorFilter();
    markNeedsPaint();
  }

  ...

  /// If non-null, this color is blended with each image pixel using [colorBlendMode].
  Color? get color => _color;
  Color? _color;
  set color(Color? value) {
    if (value == _color)
      return;
    _color = value;
    _updateColorFilter();
    markNeedsPaint();
  }

  ...

  ColorFilter? _colorFilter;
  void _updateColorFilter() {
    if (_color == null)
      _colorFilter = null;
    else
      _colorFilter = ColorFilter.mode(_color!, _colorBlendMode ?? BlendMode.srcIn);
  }

深入研究 rendering/image.dart 会发现,colorBlendMode(并且 _colorBlendMode 除了创建此 _colorFilter 之外不会在其他地方使用。

因此,我们知道 Image.network 的两个参数最终会进入 RenderImage._colorFilter

确实,_colorFilter 将在 RenderImage.paint 中用作

  @override
  void paint(PaintingContext context, Offset offset) {
    ...
    paintImage(
      canvas: context.canvas,
      rect: offset & size,
      image: _image!,
      colorFilter: _colorFilter,
      ...
    );
  }

所以我们知道了!它将在 paintImage 中使用,它与本地方法进行通信。难怪比Opacity.

还快

不要回到我们的DecorationImage。在 painting/decoration_image.dart 中,我们看到 DecorationImagePainter:

class DecorationImagePainter {
  DecorationImagePainter._(this._details, ...);

  final DecorationImage _details;

  void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration) {
    ...
    paintImage(
      canvas: canvas,
      rect: rect,
      image: _image!.image,
      colorFilter: _details.colorFilter,
      ...
    );
  }
}

嘿嘿,一模一样!

使用Opacity class。 使其子项部分透明的小部件。

Opacity(
  opacity: 0.5,
  child: Image.asset('images/lion.png'),
)