【发布时间】:2021-08-18 14:22:29
【问题描述】:
我有一堆图像小部件,当它们处于禁用状态时,它们看起来应该是灰色的。
有没有办法改变现有图像使其看起来被禁用/变灰?
我想避免同时使用启用的图像资源和禁用的图像资源来增加整体 APK 大小,而不是使用单个资源。
【问题讨论】:
标签: flutter
我有一堆图像小部件,当它们处于禁用状态时,它们看起来应该是灰色的。
有没有办法改变现有图像使其看起来被禁用/变灰?
我想避免同时使用启用的图像资源和禁用的图像资源来增加整体 APK 大小,而不是使用单个资源。
【问题讨论】:
标签: flutter
将小部件设置为容器的子级,并像这样添加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 的方法,因为容器在同一个地方为您提供了更多的灵活性。
【讨论】:
根据 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 将忽略图像的透明区域。
【讨论】:
根据我自己的个人经验,我发现将滤色器与不透明度相结合可以很好地为图像提供禁用状态。
上面显示的是我启用的图像之一的示例。
上面显示的是当您应用颜色过滤器并将不透明度小部件添加到图像时该图像的外观。
要实现类似的东西,您需要以下代码:
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)
)
)
)
)
);
【讨论】:
我改编了 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;
}
}
【讨论】:
如果你的孩子是 .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
),
),
)
【讨论】:
这个小部件实现了the Google Flutter engineer @dnfield 在this 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,
);
}
}
【讨论】:
我根据上面的 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(),
```
【讨论】:
截图:
代码:
ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.5), // 0 = Colored, 1 = Black & White
BlendMode.saturation,
),
child: Image.asset(
'chocolate_image',
fit: BoxFit.cover,
),
)
【讨论】:
但是,这是不可能的。对于运行时灰度,您可以使用带有颤振的飞镖image package。
使用 dart 图像包加载图像,应用灰度函数,从灰度图像中读取字节并将其与颤振的 Image.memory 小部件一起使用。
您可以在不为彩色图像应用灰度的情况下仅获取字节。
希望有所帮助!
【讨论】:
我认为这可以使用 alpha 来完成,它可以创建禁用的效果。这个技巧也适用于深色和浅色主题,因为它继承自父级。我用过cardColor,你可以选择任何主题并应用颜色。
Theme.of(context).cardColor.withAlpha(180)
【讨论】: