Если я использую Hero и Multiprovider вместе, я получаю сообщение об ошибке

У меня есть список карт. Когда я нажимаю на карту, BoxViewPage открыт

С Героем и без МультиПровайдера все работает корректно,

Без Героя и с Мультипровайдером все работает корректно,

но

Если я использую Hero и Multiprovider вместе, я получаю сообщение об ошибке

          return Hero(
      tag: boxID,
      child: InkWell(
        child: selectBoxSize(viewType),
        onTap: () async {
          // String path = GetArchiveLocalPath(archives, archive);
          // Box.addPhotosFromShared(path, box);
          Navigator.of(context).push(
            MaterialPageRoute(
              builder: (BuildContext context) => MultiProvider(
                providers: [
                  ChangeNotifierProvider<Archive>.value(value: archive),
                  ChangeNotifierProvider<Box>.value(value: box),
                ],
                builder: (context, child) => BoxViewPage(),
              ),
            ),
      class BoxCardView extends StatefulWidget {
  const BoxCardView({Key key}) : super(key: key);
  @override
  _BoxCardViewState createState() => _BoxCardViewState();
}

class _BoxCardViewState extends State<BoxCardView> {
  @override
  Widget build(BuildContext context) {
    return Hero(
      tag: boxID,
      child: Card(
        clipBehavior: Clip.antiAlias,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12.0),
        ),
        margin: EdgeInsets.all(12),
        child: Column(
          children: <Widget>[
            Expanded(child: WidgetEditPhotosScrollHoriz()),
            WidgetNameDescrTagsEdit(),
          ],
        ),
      ),
    );
  }
}

Ошибка:

Мы проверили исправление ProviderNotFoundException (ошибка: не удалось найти нужного поставщика выше этого виджета WidgetEditPhotosScrollHoriz).

Это происходит из-за того, что вы использовали провайдера, который не включает выбранного вами провайдера. Есть несколько распространенных сценариев:

  • Вы добавили нового провайдера в свой main.dartи выполнил горячую перезагрузку. Чтобы исправить, выполните горячий перезапуск.

  • Поставщик, которого вы пытаетесь прочитать, находится на другом маршруте.

    Провайдеры ограничены. Поэтому, если вы вставите провайдера внутрь маршрута, другие маршруты не смогут получить доступ к этому провайдеру.

  • Вы использовали BuildContextэто предок провайдера, который вы пытаетесь прочитать.

    Убедитесь, что WidgetEditPhotosScrollHoriz находится под вашим MultiProvider/Provider. Обычно это происходит, когда вы создаете провайдера и пытаетесь сразу его прочитать.

    Например, вместо:

            Widget build(BuildContext context) {
      return Provider<Example>(
        create: (_) => Example(),
        // Will throw a ProviderNotFoundError, because `context` is associated
        // to the widget that is the parent of `Provider<Example>`
        child: Text(context.watch<Example>()),
      ),
    }
    

    рассмотрите возможность использования builderвот так:

            Widget build(BuildContext context) {
      return Provider<Example>(
        create: (_) => Example(),
        // we use `builder` to obtain a new `BuildContext` that has access to the provider
        builder: (context) {
          // No longer throws
          return Text(context.watch<Example>()),
        }
      ),
    }
    

Если ни одно из этих решений не работает, рассмотрите возможность обратиться за помощью в StackOverflow:https://stackoverflow.com/questions/tagged/flutter)

2 ответа

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

Я всегда рекомендую использовать провайдер в корне вашего приложения (выше MaterialApp), это в основном лучший способ использовать его без ошибок.

Вы видите, что на самом деле здесь происходит, что провайдеры работают на основе иерархии (они предоставляют определенное значение для всех виджетов и суб-виджетов, которые вы можете сказать), и я уверен, что вы также ожидали этого, но когда мы используем навигатор вместо это родительско-дочернее отношение между виджетами - это скорее родственное отношение между страницами. Обратите внимание, что здесь я использовал слово «страницы». Ваш провайдер для вашего случая предоставляет значение только для подвиджетов той конкретной страницы, где вы его использовали, когда вы переходите на новую страницу, которая сейчас находится в верхней части стека навигации. это не подвиджет, а своего рода родственное отношение, и поэтому вы не можете получить доступ к провайдеру здесь.

Если вы этого не понимаете, не беспокойтесь, самое простое решение и визуализация для этого — просто открыть инструменты разработки dart в браузере и в инспекторе виджетов. Проверьте иерархию виджетов, вы увидите, что виджет, в котором вы хотите использовать значение, предоставленное провайдером, не находится в этой иерархии. Теперь вам нужно только выяснить, что вы должны сделать, чтобы это произошло.

Одно решение, которое я могу дать, - это просто использовать провайдера в корне приложения (выше MaterialApp).

Не могли бы вы попробовать это в своем файле списка карт:

      MaterialPageRoute(
              builder: (BuildContext context) => MultiProvider(
                providers: [
                  ChangeNotifierProvider<Archive>(
                    create: (BuildContext context) => Archive()
                  ),
                  ChangeNotifierProvider<Box>(
                    create: (BuildContext context) => Box()
                  ),
                ],
                builder: (context, child) => BoxViewPage(),
              ),
            ),
Другие вопросы по тегам