重新绘制图像时出现白色闪烁[颤动] [英] White flash when image is repainted [flutter]

查看:200
本文介绍了重新绘制图像时出现白色闪烁[颤动]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建具有给定宽度和高度的图像网格,将其包裹在Containers内,并使用fit: BoxFit.fill以便能够在选择图像时设置边框(我不在乎保持图像的宽高比,我希望每个容器的总宽度和高度都相同.

I'm trying to build a grid of images with a given width and height, wrapping them inside Containers and using fit: BoxFit.fill to be able to set a border if the image is selected (i don't care to keep the image aspect ratio, i want to have the same total width and height for each container).

问题是当点击图像后重新绘制图像时,我注意到白色闪烁. 当图像很少时,似乎不会发生这种情况,但是当图像超过15张时,这很嘈杂.

The problem is that i notice a white flash when the image gets repainted after it has been tapped on. This seems not to happen when there are few images, but with 15+ images it is noisy.

我尝试在图像小部件上添加gaplessPlayback: true,因为我在此处,但这并不能解决我的问题.

I tried to add gaplessPlayback: true on the image widget, as i found here, but this did not solve my issue.

以下是显示我的问题的gif文件(我使用了16张图片,尺寸为1920x1080):

Here's a gif that shows my issue (i used 16 images, size is 1920x1080):

我忘了指出这只是一个例子,我在代码中使用了边框,但就我而言,我还想向容器中添加填充以使图像变小(例如在android照片库中),表示点击的图像应该每次重新绘制.

I forgot to point out that this is just an example, i used a border in the code but in my case i want also to add a padding to the container to make the image smaller (like in android photo gallery), this means that the tapped image should repaint every time.

这是我的代码:

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;
              }),
            ),
          ),
        ),
      ),
    );
  }
}

我该如何解决?谢谢!

推荐答案

这可能是由于1. ImageCache约束和2.将所有图像嵌套在Wrap

This is probably because of a mix of 1. ImageCache constraints and 2. Nesting all your images within Wrap

ImageCache具有可缓存在内存中的最大图像数,以及最大总字节数.当达到该限制时,旧图像将被驱逐,以腾出空间容纳新图像.尝试显示以前从缓存中撤出的图像时,将需要一些时间才能将其再次加载到内存中,因此会出现白色闪烁.您可以按照更改缓存的限制如何在Flutter中更改或替换ImageCache?

The ImageCache has a maximum number of images that it can cache in memory, as well as a maximum number of total bytes. When that limit is reached, old images are evicted to make space for new ones. When trying to display an image that was previously evicted from cache, it will take some time to load it into memory again, therefore the white flash. You can change the limits of the cache as per How do I change or replace the ImageCache in Flutter?

默认图像缓存限制为1000张不同的图像,总共100MiB,通常在不构建屏幕外小部件的最佳布局下就足够了.

The default image cache limits are 1000 different images and a total of 100MiB, which are usually enough given an optimal layout where off-screen widgets are not built.

Wrap可能是您遇到问题的主要原因-我相信它会在内部构建其所有子项,以便弄清楚如何包装它们.在您的情况下,将是所有图像.可能是由于Wrap,您的所有图像都被视为在屏幕上,因此没有从缓存中逐出-这可以解释为什么即使您不重建整个窗口小部件树,GIF中的某些图像也会闪烁-因为这些图像没有被缓存,因为缓存已满,没有图像可以被驱逐.

Wrap might be the main reason of your problem - I believe it internally builds all of its children in order to figure out how to wrap them. In your case, that would be all of the images. It may be that because of the Wrap, all your images are considered on-screen and therefore not evicted from cache - this would explain why some of the images in the GIF are flashing even though you are not rebuilding the entire widget tree - because those images are not cached because the cache is full and none of the images can be evicted.

您可能希望将Wrap替换为GridView.builder,这只会生成屏幕小部件.

You might want to replace Wrap with a GridView.builder, which will only build the on-screen widgets.

如果图像太大而无法容纳与一次显示的缓存数量相同的图像,那么您可能会遇到同样的问题.如果您在10x10的容器中显示50MB的图像,则仍然需要50MB的内存缓存.

You could have the same issue if the images are simply too large to fit as many in the cache as you are displaying at once. If you display a 50MB image in a 10x10 container, that still takes 50MB of in-memory cache.

这篇关于重新绘制图像时出现白色闪烁[颤动]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆