重新绘制图像时出现白色闪烁[颤动]
Posted
技术标签:
【中文标题】重新绘制图像时出现白色闪烁[颤动]【英文标题】:White flash when image is repainted [flutter] 【发布时间】:2020-05-24 07:42:26 【问题描述】:我正在尝试构建一个具有给定宽度和高度的图像网格,将它们包裹在Containers
中并使用fit: BoxFit.fill
在选择图像时设置边框(我不在乎保持图像纵横比,我希望每个容器的总宽度和高度相同)。
问题是,当图像在被点击后被重新绘制时,我注意到一个白色的闪光。 当图像很少时,这似乎不会发生,但如果图像超过 15 个,则会出现噪音。
我尝试在图像小部件上添加gaplessPlayback: true
,因为我找到了here,但这并没有解决我的问题。
这是显示我的问题的 gif(我使用了 16 张图片,尺寸为 1920x1080):
编辑:
我忘了指出这只是一个例子,我在代码中使用了边框,但在我的情况下,我还想在容器中添加一个填充以使图像更小(就像在 android 照片库中一样),这个表示每次点击的图像都应该重新绘制。
这是我的代码:
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main()
// See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: ImageGridView()),
);
class ImageGridView extends StatelessWidget
List<File> _fileList = [];
ImageGridView()
_fileList = [
File('C:/flutter/img/1.jpg'),
File('C:/flutter/img/3.jpg'),
File('C:/flutter/img/4.jpg'),
File('C:/flutter/img/5.jpg'),
File('C:/flutter/img/6.jpg'),
File('C:/flutter/img/7.jpg'),
File('C:/flutter/img/8.jpg'),
File('C:/flutter/img/9.jpg'),
File('C:/flutter/img/10.jpg'),
File('C:/flutter/img/11.jpg'),
File('C:/flutter/img/12.jpg'),
File('C:/flutter/img/13.jpg'),
File('C:/flutter/img/14.jpg'),
File('C:/flutter/img/15.jpg'),
File('C:/flutter/img/16.jpg'),
];
@override
Widget build(BuildContext context)
return SingleChildScrollView(
child: Wrap(
children: _fileList.map((file)
return WindowsAsset(file);
).toList(),
),
);
class WindowsAsset extends StatefulWidget
final File _file;
WindowsAsset(this._file);
@override
State<StatefulWidget> createState() => WindowsAssetState();
class WindowsAssetState extends State<WindowsAsset>
bool selected = false;
@override
Widget build(BuildContext context)
final width = MediaQuery.of(context).size.width / 2;
final height = width * 1080 / 1920;
return Container(
width: width,
height: height,
child: Container(
child: Container(
constraints: BoxConstraints.expand(),
decoration: !selected
? null
: BoxDecoration(
border: Border.all(
color: Color.fromRGBO(153, 209, 255, 1),
width: 4
),
),
child: Container(
child: GestureDetector(
child: Image.file(
widget._file,
filterQuality: FilterQuality.medium,
fit: BoxFit.fill,
gaplessPlayback: true,
),
onTap: () => setState(()
selected = !selected;
),
),
),
),
),
);
我该如何解决?谢谢!
【问题讨论】:
我认为您应该使用堆栈并在图像上绘制一个容器,而不是更改图像父容器边框 @veneno 感谢您的评论,我忘了指出我的只是一个例子,我在代码中只使用了一个边框,但在我的情况下,我还想为容器添加一个填充,这意味着每次点击的图像都应该重新绘制 【参考方案1】:这可能是因为 1. ImageCache 约束和 2. 将所有图像嵌套在 Wrap
中
ImageCache 具有可缓存在内存中的最大图像数,以及最大总字节数。当达到该限制时,旧图像将被逐出以为新图像腾出空间。当尝试显示之前从缓存中清除的图像时,需要一些时间才能再次将其加载到内存中,因此会出现白色闪烁。您可以根据How do I change or replace the ImageCache in Flutter?更改缓存的限制
默认的图像缓存限制是 1000 个不同的图像,总共 100MiB,如果没有构建离屏小部件的最佳布局,这通常就足够了。
Wrap
可能是您的问题的主要原因 - 我相信它会在内部构建所有子代,以便弄清楚如何包装它们。在您的情况下,这将是所有图像。可能是因为Wrap
,您的所有图像都被视为在屏幕上,因此不会从缓存中清除 - 这可以解释为什么即使您没有重建整个小部件树,GIF 中的某些图像也会闪烁 -因为这些图像没有被缓存,因为缓存已满,并且没有一个图像可以被驱逐。
您可能希望将Wrap
替换为GridView.builder
,这样只会构建屏幕小部件。
如果图像太大而无法在缓存中容纳与您一次显示的一样多的图像,您可能会遇到同样的问题。如果您在 10x10 容器中显示 50MB 的图像,则仍需要 50MB 的内存缓存。
【讨论】:
感谢您的回答和解释,我会尝试您的解决方案并告诉您! 我尝试使用 GridView.builder 方法,但结果是一样的。但是,我现在正在使用 ImageCache,您认为 Image.file 默认会缓存图像吗?如果我使用您发布的链接中的代码并打印 imageCache.maximumSizeBytes 它告诉我它已经是 100MB(总共 1000 张图像),所以我应该没有任何问题,因为我使用的是 16 张图像并且总量大小是大约 10MB 是的,所有Image
构造函数都会导致图像被缓存,包括Image.file
。在点击图像时尝试检查ImageCache
的currentSize
和currentSizeBytes
的值 - 这将阐明问题是ImageCache
还是其他问题。
好吧,我不知道为什么,但 currentSizeBytes 大于 100 MB,即使图像的总大小约为 10 MB。如果我设置了一个巨大的最大尺寸,白色闪光就会消失。以后会考虑的,谢谢!
仅供参考,我正在使用 Wrap() 处理我的图像,而 Image() 小部件上的 gaplessPlayback: true
解决了我的闪烁问题。【参考方案2】:
将图片的gaplessPlayback
设置为true
。
Image.memory(
thumbData,
gaplessPlayback: true,
)
【讨论】:
以上是关于重新绘制图像时出现白色闪烁[颤动]的主要内容,如果未能解决你的问题,请参考以下文章