Flutter: преобразование виджета в изображение сразу после setState не показывает изменений

Я несколько дней боролся с проблемой, и я начинаю задаваться вопросом, есть ли у нее достойное решение.

У меня есть карта Google, на которой я хочу показать разные пользовательские маркеры, каждый из которых создается с информацией, поступающей из вызова API.

Для этого я использую виджет Stack, у которого есть RepaintBoundary, расположенный под картой Google, поэтому он скрыт. Этот RepaintBoundary имеет изображение и текстовую метку.

Widget build(BuildContext context) {
return new Scaffold(
  body: Stack(
    children: [
      RepaintBoundary(
        key: iconKey,
        child:
        Stack(
            children: [
              markerIconButton,
              markerText,
            ]
        ),
      ),
      GoogleMap(
        mapType: MapType.normal,
        myLocationEnabled: true,
        myLocationButtonEnabled:true,
        onMapCreated: _onMapCreated,
        markers: Set<Marker>.of(_markers),
      ),
    ]
  ),
),

}

Когда я хочу разместить маркеры, я перебираю результаты вызова API и на каждой итерации пытаюсь изменить изображение и текст RepaintBoundary, преобразовать его в изображение, а затем назначить его новому маркеру. , я использую этот фрагмент кода:

...
 for (dynamic result in results) {
     ...
     markerText = result["text"];
     backgroundImage = result["assets_image_path"];
     setState((){
        markerIconButton = new Image.asset(backgroundImage);
        markerText = new Text(markerText);
      });

      // Convert the widget to image
      BitmapDescriptor testIcon = await getCustomIcon(iconKey);

      Marker marker = Marker(
          markerId: MarkerId(index.toString()),
          position: LatLng(
              result["latitude"],
              result["longitude"]
          ),
          icon: testIcon,
      );

      setState((){
        _markers.add(marker);
      });
      index++;
 }

Проблема в том, что когда я вызываю getCustomIcon, который использует метод RenderRepaintBoundary.toImage, новый текст и изображение еще не были отрисованы, поэтому изображение, переданное в качестве значка маркеру текущей итерации, обычно принадлежит предыдущей итерации. Есть ли способ запустить код, который преобразует виджет в изображение, гарантируя, что изменения в изображении и тексте были отображены?

Я попытался сначала сгенерировать все изображения в цикле и сохранить их в списке с помощью WidgetsBinding.instance.addPostFrameCallback, но когда я удаляю код для добавления каждого маркера из цикла, пропускается много кадров, и только изображение и отображается текст последней итерации.

Заранее спасибо.


person gruiz    schedule 16.04.2021    source источник
comment
вы не даете фреймворку времени для создания вашего пользовательского интерфейса перед преобразованием в изображение. setState является асинхронным и выполняется, когда у фреймворка есть на это время. Попробуйте добавить задержку: setState((){ markerIconButton = new Image.asset(backgroundImage); markerText = new Text(markerText); }); Future.delayed(Длительность(миллисекунды: 2000)); // Конвертируем виджет в изображение BitmapDescriptor testIcon = await getCustomIcon(iconKey);   -  person moulte    schedule 16.04.2021
comment
Я уже протестировал это, и это работает, но это оказывает огромное влияние на производительность, представьте, что у вас есть 30 маркеров для отображения. Кроме того, у вас нет 100% гарантии, что он отрендерится независимо от того, сколько времени вы укажете в задержке. Я думал, что должен быть способ вызвать что-то после рендера.   -  person gruiz    schedule 19.04.2021
comment
да, я согласен, но я не нашел этого способа, вы, вероятно, можете уменьшить задержку, 2000 мс были просто примером   -  person moulte    schedule 19.04.2021


Ответы (1)


вы не даете фреймворку времени для создания вашего пользовательского интерфейса перед преобразованием в изображение. setState является асинхронным и выполняется, когда у фреймворка есть на это время. Попробуйте добавить задержку:

 setState((){
    markerIconButton = new Image.asset(backgroundImage);
    markerText = new Text(markerText);
  });
  Future.delayed(Duration(milliseconds: 2000));
  // Convert the widget to image
  BitmapDescriptor testIcon = await getCustomIcon(iconKey);
person moulte    schedule 19.04.2021