flutter - Flutter ShaderMask 使用 ImageShader
问题描述
我正在尝试ShaderMask
使用图像作为着色器。我正在从内存中读取图像,所以我的图像是File
. 如何使用内存中的图像创建 ImageShader?
File imageFile;
Image image = Image.file(imageFile)
ShaderMask(
shaderCallback: (bounds) {
Float64List matrix4 = new Matrix4.identity().storage; // <--- DO I NEED THIS OR THE BOUNDS?
return ImageShader(image, TileMode.mirror, TileMode.mirror, matrix4);
},
child: child
)
由于图像类型错误ImageShader
(我需要 ui.Image,我不明白如何创建),因此出现错误。
如何ImageShader
从File
图像创建?
PS:是matrix4
正确的还是我应该以某种方式使用边界?
解决方案
重要的是要知道它ImageShader
使用dart:ui
包中的图像而不是Image
小部件的实例。没有可用于ui.Image
从网络位置、文件或资产创建实例的直接操作或构造函数,因此您需要一些代码来完成它。
在查找许多资源并深入研究小部件如何加载原始图像的代码后,我想出的最佳通用解决方案Image
是使用ImageProvider
作为源。抽象ImageProvider
具有像NetworkImage
,和之类的实现FileImage
,可以从您想要的任何资源加载您的图像。ExactAssetImage
MemoryImage
首先你得到一个ImageStream
usingImageProvider.resolve
方法。该resolve
方法采用 type 的参数,该参数ImageConfiguration
应填充您在代码位置可用的尽可能多的信息。在大多数情况下,您可以使用全局函数,但请注意,当您在StatefulWidgetcreateLocalImageConfiguration
的方法中创建着色器时,这将不起作用。initState
在已解决的情况下,ImageStream
您可以附加一个ImageStreamListener
, 将ImageListener
回调作为第一个参数。加载图像后,将使用 调用回调ImageInfo
,它在属性上提供请求的图像image
。
您可以ImageShader
使用这两种平铺模式TileMode.clamp
和一个简单的单位矩阵来构建 ,您可以手动创建或使用Matrix4
该类提供的那个。如果您需要图像着色器小于所提供图像的大小,您可以将您的提供程序包装在 an 中ResizeProvider
并指定所需的宽度和高度。
下面我实现了一个ImageMask
小部件作为参考,它可以用来屏蔽任何类型的小部件。
class ImageMask extends StatefulWidget {
final ImageProvider image;
final double width;
final double height;
final Widget child;
const ImageMask({@required this.image, this.width, this.height, @required this.child});
@override
_ImageMaskState createState() => _ImageMaskState();
}
class _ImageMaskState extends State<ImageMask> {
Future<Shader> _shader;
@override
void initState() {
super.initState();
_shader = _loadShader(context);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _shader,
builder: (_, AsyncSnapshot<Shader> snapshot) {
return snapshot.connectionState != ConnectionState.done || snapshot.hasError
? SizedBox(width: widget.width, height: widget.height)
: ShaderMask(
blendMode: BlendMode.dstATop,
shaderCallback: (bounds) => snapshot.data,
child: widget.child,
);
},
);
}
Future<Shader> _loadShader(BuildContext context) async {
final completer = Completer<ImageInfo>();
// use the ResizeImage provider to resolve the image in the required size
ResizeImage(widget.image, width: widget.width.toInt(), height: widget.height.toInt())
.resolve(ImageConfiguration(size: Size(widget.width, widget.height)))
.addListener(ImageStreamListener((info, _) => completer.complete(info)));
final info = await completer.future;
return ImageShader(
info.image,
TileMode.clamp,
TileMode.clamp,
Float64List.fromList(Matrix4.identity().storage),
);
}
}
推荐阅读
- php - 难以在 Facebook-PHP-SDK 中授权应用程序
- json - 在序列化/反序列化 Avro Record 后,在 Scala 中将 java.util.HashMap 转换为 JSON
- python - 如何在数组维度不同时评估表达式
- node.js - 为什么不能在反应前端工作 nodejs 脚本?
- prometheus - Prometheus 错误 - 摄取样本时出错
- google-maps - 按新鲜度排序?
- salesforce - 没有从 Salesforce Streaming API 推送主题频道收到消息
- python - 替代使用所有 26 个字母的 hexdigest?
- android - 如何在 Processing for android 中正确添加图像
- python - 如何用两个列分组值的中值替换数据框中的空值?