Белая вспышка при перекрашивании изображения [дрожание]

Я пытаюсь построить сетку изображений с заданной шириной и высотой, обернув их внутрь Containers и используя fit: BoxFit.fill, чтобы иметь возможность установить границу, если изображение выбрано (я не хочу сохранять соотношение сторон изображения, я хотите иметь одинаковую общую ширину и высоту для каждого контейнера).

Проблема в том, что я замечаю белую вспышку, когда изображение перекрашивается после нажатия на него. Кажется, что этого не происходит, когда изображений мало, но с 15+ изображениями это шумно.

Я попытался добавить gaplessPlayback: true в виджет изображения, так как нашел здесь , но этого не произошло. решить мою проблему.

Вот гифка, которая показывает мою проблему (я использовал 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;
              }),
            ),
          ),
        ),
      ),
    );
  }
}

Как я могу это решить? Спасибо!


person Ansharja    schedule 08.02.2020    source источник
comment
Я думаю, вам следует использовать стек и нарисовать контейнер поверх изображения вместо изменения границы родительского контейнера изображения   -  person veneno    schedule 08.02.2020
comment
@veneno Спасибо за ваш комментарий, я забыл указать, что мой был просто примером, я использовал только рамку в коде, но в моем случае я хочу также добавить отступ к контейнеру, это означает, что изображение с нажатым изображением должно перерисоваться каждый раз   -  person Ansharja    schedule 08.02.2020


Ответы (1)


Вероятно, это из-за сочетания 1. ограничений ImageCache и 2. вложенности всех ваших изображений в Wrap

ImageCache имеет максимальное количество изображений, которые он может кэшировать в памяти, а также максимальное общее количество байтов. По достижении этого предела старые изображения удаляются, чтобы освободить место для новых. При попытке отобразить изображение, которое ранее было удалено из кеша, потребуется некоторое время, чтобы снова загрузить его в память, поэтому белая вспышка. Вы можете изменить пределы кеша согласно Как изменить или заменить ImageCache во Flutter?

Пределы кэша изображений по умолчанию составляют 1000 различных изображений и в общей сложности 100 МБ, что обычно достаточно при оптимальном макете, при котором виджеты вне экрана не создаются.

Wrap может быть основной причиной вашей проблемы - я считаю, что он внутренне строит всех своих дочерних элементов, чтобы выяснить, как их обернуть. В вашем случае это будут все изображения. Может случиться так, что из-за Wrap все ваши изображения считаются отображаемыми на экране и, следовательно, не удаляются из кеша - это объясняет, почему некоторые изображения в GIF мигают, даже если вы не перестраиваете все дерево виджетов - потому что эти изображения не кэшируются, потому что кеш заполнен и ни одно из изображений не может быть удалено.

Возможно, вы захотите заменить Wrap на GridView.builder, который будет создавать только экранные виджеты.

У вас может быть такая же проблема, если изображения слишком велики, чтобы поместиться в кеше, сколько вы отображаете одновременно. Если вы отображаете изображение размером 50 МБ в контейнере 10x10, это по-прежнему занимает 50 МБ кеш-памяти в памяти.

person Ovidiu    schedule 08.02.2020
comment
Спасибо за ваш ответ и объяснение, я попробую ваше решение и дам вам знать! - person Ansharja; 08.02.2020
comment
Я пробовал использовать метод GridView.builder, но результат тот же. Однако я сейчас немного играю с ImageCache. Как вы думаете, Image.file кэширует изображения по умолчанию? Если я использую код в опубликованной вами ссылке и распечатываю imageCache.maximumSizeBytes, он сообщает мне, что это уже 100 МБ (всего 1000 изображений), поэтому у меня не должно возникнуть никаких проблем, так как я использую 16 изображений, а общий размер составляет около 10 МБ - person Ansharja; 09.02.2020
comment
Да, все конструкторы Image приведут к кэшированию изображений, включая Image.file. Попробуйте проверить значения currentSize и currentSizeBytes из ImageCache при нажатии на изображения - это прояснит, связана ли проблема с ImageCache или чем-то еще. - person Ovidiu; 09.02.2020
comment
Хорошо, я не знаю почему, но currentSizeBytes был больше 100 МБ, даже если общий размер изображений составляет около 10 МБ. Если я установил очень большой максимальный размер, белая вспышка исчезнет. Я рассмотрю это в будущем, спасибо! - person Ansharja; 09.02.2020
comment
Установка imageCache.maximumSizeBytes = 9999999999; у меня сработало! - person Syed Saad; 18.02.2021