【问题标题】:Making an Image widget disabled / grayed out使图像小部件禁用/变灰
【发布时间】:2021-08-18 14:22:29
【问题描述】:

我有一堆图像小部件,当它们处于禁用状态时,它们看起来应该是灰色的。

有没有办法改变现有图像使其看起来被禁用/变灰?

我想避免同时使用启用的图像资源和禁用的图像资源来增加整体 APK 大小,而不是使用单个资源。

【问题讨论】:

    标签: flutter


    【解决方案1】:

    将小部件设置为容器的子级,并像这样添加foregroundDecoration:

    Container(
      foregroundDecoration: BoxDecoration(
        color: Colors.grey,
        backgroundBlendMode: BlendMode.saturation,
      ),
      child: child,
    )
    

    -- 更新: 基于颤振团队的this new video,还有另一个小部件。 代码基本一样,是这样的:

    ColorFiltered(
      colorFilter: ColorFilter.mode(
        Colors.grey,
        BlendMode.saturation,
      ),
      child: child,
    )
    

    但我仍然更喜欢使用 Container forgroundDecoration 的方法,因为容器在同一个地方为您提供了更多的灵活性。

    【讨论】:

    • 我可以将灰度值调整为浅灰色吗?
    • 不幸的是,这似乎也将过滤器应用于图像的背景。有没有办法避免这种情况?
    • @TinMan 检查我在更新部分添加的视频链接。使用 image.Asset 小部件中的颜色参数。
    • @stanliu 当然,您可以将颜色更改为您想要的任何颜色。 :)
    • @SinaSeirafi 不幸的是,ColorFiltered 仍然不能处理透明度:(
    【解决方案2】:

    根据 ColorFiltered 的颤振文档,您可以像这样使用 ColorFilter.matrix link

    const ColorFilter greyscale = ColorFilter.matrix(<double>[
      0.2126, 0.7152, 0.0722, 0, 0,
      0.2126, 0.7152, 0.0722, 0, 0,
      0.2126, 0.7152, 0.0722, 0, 0,
      0,      0,      0,      1, 0,
    ]);
    
    ColorFiltered(
      colorFilter: greyscale,
      child: child,
    );
    

    在这种情况下,ColorFilter 将忽略图像的透明区域。

    【讨论】:

    【解决方案3】:

    根据我自己的个人经验,我发现将滤色器与不透明度相结合可以很好地为图像提供禁用状态。

    上面显示的是我启用的图像之一的示例。

    上面显示的是当您应用颜色过滤器并将不透明度小部件添加到图像时该图像的外观。

    要实现类似的东西,您需要以下代码:

      new Material(
          elevation: 2.0,
          child: new Opacity(
            opacity: 0.3,
            child: new Container(
              padding: new EdgeInsets.all(20.0),
              child: new Image.asset("assets/<your icon>", fit: BoxFit.cover, color: Colors.grey),
              decoration: new BoxDecoration(
                border: new Border.all(
                  width: 2.0, color: const Color(0x40000000)),
                  borderRadius: const BorderRadius.all(const Radius.circular(5.0)
                )
              )
            )
          )
      );
    

    【讨论】:

      【解决方案4】:

      我改编了 Mark O'Sullivan 的帖子并创建了一个通用小部件:

      使用它:

      text = Text("Hellow World");
      GrayedOut(text);
      

      GrayedOut(text, grayedOut: true);
      

      还有班级

      class GrayedOut extends StatelessWidget {
        final Widget child;
        final bool grayedOut;
      
        GrayedOut(this.child, {this.grayedOut = true});
      
        @override
        Widget build(BuildContext context) {
          return grayedOut ? new Opacity(opacity: 0.3, child: child) : child;
        }
      }
      

      【讨论】:

      • 这个解决方案不是 OP 所要求的,而是它只是包装了一个 Opacity 小部件。如果将其应用于彩色图像,它不会变灰而只会变淡。
      【解决方案5】:

      如果你的孩子是 .png 图像,如果你输入Colors.grey,flutter 会将其渲染为灰色背景。使用与您的小部件背景相同的颜色,您将拥有完美的禁用图像

      ColorFiltered(
          colorFilter: ColorFilter.mode(
              Colors.white,
              BlendMode.saturation,
          ),
          child: child,
      )
      

      如果你想在用户点击图片时改变图片的颜色,你可以这样做:

      GestureDetector(
      
          onTap: () => {
      
              setState((){
      
                  _active = !_active;
      
              })
          
          },
          child: ColorFiltered(
          
              colorFilter: _active ? ColorFilter.mode(
                                                                                       
                  Colors.transparent,                                                          
                  BlendMode.saturation,
      
              ) : ColorFilter.mode(
                                                                               
                  Colors.white,
                  BlendMode.saturation,
              ),
      
              child: Image(
      
                  image: Image.asset("assets/test.png").image
                 
              ),
          ),
      )
      

      【讨论】:

        【解决方案6】:

        这个小部件实现了the Google Flutter engineer @dnfieldthis Flutter GitHub issue 上所说的内容,它适用于具有透明背景的图像。

        import 'package:flutter/widgets.dart';
        
        class GrayscaleColorFiltered extends StatelessWidget {
          final Widget child;
        
          const GrayscaleColorFiltered({Key? key, required this.child}) : super(key: key);
        
          @override
          Widget build(BuildContext context) {
            return ColorFiltered(
              colorFilter: ColorFilter.matrix(<double>[
                0.2126, 0.7152, 0.0722, 0, 0, //
                0.2126, 0.7152, 0.0722, 0, 0,
                0.2126, 0.7152, 0.0722, 0, 0,
                0, 0, 0, 1, 0,
              ]),
              child: child,
            );
          }
        }
        
        

        【讨论】:

        • 这应该是公认的答案,因为它完美地避免了弄乱孩子的透明度。
        • 很高兴你这么认为,@wangpan! :·)
        【解决方案7】:

        我根据上面的 Marks 答案创建了一个小部件:

        import 'package:flutter/material.dart';
        
        class DisabledRenderer extends StatelessWidget {
          final Widget child;
          final bool enabled;
          final double padding;
          final double boxWidth;
          final Color boxColor;
          final double boxRadius;
        
          DisabledRenderer(
              {@required this.child,
              @required this.enabled,
              this.padding = 2,
              this.boxWidth = 2,
              this.boxColor = Colors.white,
              this.boxRadius = 5.0});
        
          @override
          Widget build(BuildContext context) => Material(
                elevation: 2.0,
                child: Opacity(
                  opacity: enabled ? 1 : 0.3,
                  child: Container(
                    padding: EdgeInsets.all(padding),
                    child: child,
                    decoration: BoxDecoration(
                      border: Border.all(width: boxWidth, color: boxColor),
                      borderRadius: BorderRadius.all(Radius.circular(boxRadius)),
                    ),
                  ),
                ),
              );
        }
        

        使用中是这样的:

        DisabledRenderer(enabled: false, child: Icon(MdiIcons()['speedometer'],);
        

        enable bool 通常与 StreamBuilder 一起使用来监听模型事件。 具体方法请搜索 Flutter Bloc pattern 和 StreamBuilder

        如果您需要支持流(块模式)的版本,请使用此版本:

        import 'package:flutter/material.dart';
        
        class DisabledRenderer extends StatelessWidget {
          final Widget child;
          final bool enabled;
          final Stream enableStream;
          final double padding;
          final bool showBorder;
          final double boxWidth;
          final Color boxColor;
          final double boxRadius;
        
          DisabledRenderer(
              {@required this.child,
              this.enabled,
              this.enableStream,
              this.showBorder = true,
              this.padding = 2,
              this.boxWidth = 2,
              this.boxColor = Colors.white,
              this.boxRadius = 5.0}) {
            //one or the other, not both
            assert((enableStream != null && enabled == null) ||
                (enableStream == null && enabled != null));
          }
        
          @override
          Widget build(BuildContext context) => Material(
                elevation: 2.0,
                child: enableStream != null
                    ? StreamBuilder<bool>(
                        initialData: false,
                        stream: enableStream,
                        builder: (BuildContext context, AsyncSnapshot enabled) {
                          return enabled.hasData
                              ? _renderEnabledDisabledState(enabled.data)
                              : Container();
                        },
                      )
                    : _renderEnabledDisabledState(enabled),
              );
        
          Widget _renderEnabledDisabledState(bool enabled) {
            return IgnorePointer(
              ignoring: !enabled,
              child: Opacity(
                opacity: enabled ? 1 : 0.3,
                child: showBorder
                    ? Container(
                        padding: EdgeInsets.all(padding),
                        child: child,
                        decoration: BoxDecoration(
                          border: Border.all(width: boxWidth, color: boxColor),
                          borderRadius: BorderRadius.all(Radius.circular(boxRadius)),
                        ),
                      )
                    : child,
              ),
            );
          }
        }
        

        这就是你将如何使用它:

        DisabledRenderer(
                         showBorder: false,
                         enableStream: BlocProvider.of(context)
                                              .bluetooth
                                              .isConnected
                                              .stream,
                         child: YourWidget(),
            ```
        
        
        
        

        【讨论】:

        • 我不介意人们是否投票否决解决方案。如果您能简要说明问题所在,我们都可以从中吸取教训,因为我们在这里做出了诚实的努力,这将是很好的。谢谢。
        • 您的小部件看起来与您的项目耦合。为什么您的班级中存在流?而且您的代码并没有抽象出项目的复杂性。顺便说一句:反对票不是我的。
        • 它与我的项目没有耦合。它是一个通用的例子。启用状态可以来自启用布尔或来自流。流经常用于 Flutter / dart 项目中。最后一个示例显示了我如何在项目中使用它,但小部件本身是通用的。
        • 你是对的,你的组件并没有真正耦合。在这种组件中看到布尔值流只是感觉很奇怪,但我看到你也暴露了一个简单的布尔值。
        • 如果您在模型中使用流,您可以直接使用它,无需 StreamBuilder 等。非常方便。
        【解决方案8】:

        截图:


        代码:

        ColorFiltered(
          colorFilter: ColorFilter.mode(
            Colors.black.withOpacity(0.5), // 0 = Colored, 1 = Black & White
            BlendMode.saturation,
          ),
          child: Image.asset(
            'chocolate_image',
            fit: BoxFit.cover,
          ),
        )
        

        Source

        【讨论】:

          【解决方案9】:

          但是,这是不可能的。对于运行时灰度,您可以使用带有颤振的飞镖image package。 使用 dart 图像包加载图像,应用灰度函数,从灰度图像中读取字节并将其与颤振的 Image.memory 小部件一起使用。

          您可以在不为彩色图像应用灰度的情况下仅获取字节。

          希望有所帮助!

          【讨论】:

            【解决方案10】:

            我认为这可以使用 alpha 来完成,它可以创建禁用的效果。这个技巧也适用于深色和浅色主题,因为它继承自父级。我用过cardColor,你可以选择任何主题并应用颜色。

            Theme.of(context).cardColor.withAlpha(180)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-08-04
              • 1970-01-01
              • 2010-09-22
              • 1970-01-01
              • 1970-01-01
              • 2023-03-09
              • 1970-01-01
              相关资源
              最近更新 更多