Why Hero doesn't work with Multiprovider?

197

As much as I understand I think your problem is also one of the typical ones while using providers.

I always recommend using provider at the root of your application (above MaterialApp), that is mainly the best way to use it without running into errors.

You see actually what is happening here, that providers work based on hierarchy (They provide a specific value to all widgets and sub-widgets you can say) and I'm sure you were also expecting this, But when we use a navigator instead of this parent child relation between widgets it is more of a Sibling-relation between pages. Note down I used the word pages here, Your provider for your case is only providing the value to the sub-widgets of that specific page where you used it, when you navigate to the new page that is now on the top of the navigation stack is not a sub-widget, rather it is sort of sibling relation and hence you cannot access the provider here.

If you do not understand this, do not worry simplest solution and visualization for this is just to open up dart dev tools on browser and in the Widgets Inspector, Check out the widget Hierarchy, you will observe that the widget where you want to use the value provided by the provider is not under that hierarchy, Now you only need to figure out what you should do to make it happen.

One solution I can give is just to Use the provider at the root of application (Above MaterialApp).

Share:
197
Ricky
Author by

Ricky

Updated on December 01, 2022

Comments

  • Ricky
    Ricky over 1 year

    I have a list of cards. When I tap a card, the BoxViewPage opens.

    If I use Hero and Multiprovider together, I get an error,

    but,

    if I use Hero and MultiProvider individually everything works correctly

    Why?

    List of Cards:

        return Hero(
          tag: box.ID,
          child: InkWell(
            child: selectBoxSize(viewType),
            onTap: () async {
              Navigator.of(context).push(
                MaterialPageRoute(
                  builder: (BuildContext context) => MultiProvider(
                    providers: [
                      ChangeNotifierProvider<Archive>.value(value: archive),
                      ChangeNotifierProvider<Box>.value(value: box),
                    ],
                    builder: (context, child) => BoxViewPage(),
                  ),
                ),
    

    Inside 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) {
        final box = Provider.of<Box>(context);
        return Hero(
          tag: box.ID,
          child: Card(
            clipBehavior: Clip.antiAlias,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(12.0),
            ),
            margin: EdgeInsets.all(12),
            child: Column(
              children: <Widget>[
                Expanded(child: WidgetEditPhotosScrollHoriz()),
                WidgetNameDescrTagsEdit(),
              ],
            ),
          ),
        );
      }
    }
    

    Error:

    Si è verificata un'eccezione ProviderNotFoundException (Error: Could not find the correct Provider above this WidgetEditPhotosScrollHoriz Widget

    This happens because you used a BuildContext that does not include the provider of your choice. There are a few common scenarios:

    • You added a new provider in your main.dart and performed a hot-reload. To fix, perform a hot-restart.

    • The provider you are trying to read is in a different route.

      Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.

    • You used a BuildContext that is an ancestor of the provider you are trying to read.

      Make sure that WidgetEditPhotosScrollHoriz is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately.

      For example, instead of:

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

      consider using builder like so:

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

    If none of these solutions work, consider asking for help on StackOverflow: https://stackoverflow.com/questions/tagged/flutter )

    • Felipe Morschel
      Felipe Morschel about 2 years
      Are you using provider inside the WidgetEditPhotosScrollHoriz?
    • Mahdi Arabpour
      Mahdi Arabpour about 2 years
      do you use a Navigator widget anywhere in your widget tree?
    • Ricky
      Ricky about 2 years
      Yes, I use Navigator to change pages and normally I put the MultiProvider Builder inside the Navigator.Push method
    • Mahdi Arabpour
      Mahdi Arabpour about 2 years
      No I mean a custom 'Navigator' widget in widget tree!
    • Ricky
      Ricky about 2 years
      no, any custom 'Navigator'
    • Jodeveloper8
      Jodeveloper8 about 2 years
  • Ricky
    Ricky about 2 years
    if I put provider Above MaterialApp, Hero works, but I need to change values of provider during the navigation in other pages so I can't put it above Material App
  • KaZami-Ryu
    KaZami-Ryu about 2 years
    you can create your own custom class which stores the value then create a method to set and get its value (also use notifylistners after inherting it from ChangeNotifier class), And you can use provider for that new custom class now.