skip to Main Content

would need some advice. I try to implement showSearch in appBar and have a LocationSearchDelegate() class with SearchDelegate in it. There is no error in my code, but when I run it and click on the search button it shows:

══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a
descendant of a Navigator widget.

here’s my code in main.dart

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("Raincheck"),
          actions: [
            IconButton(
              icon: const Icon(Icons.search),
              onPressed: () {
                showSearch(
                  context: context,
                  delegate: LocationSearchDelegate(),
                );
              },
            ),
            //   IconButton(
            //     onPressed: () {},
            //     icon: const Icon(Icons.settings),
            //   )
          ],
        ),
        body: const Center(
          child: HomePage(),
        ),
      ),
    );
  }
}

and here is my LocationSearchDelegate()

class LocationSearchDelegate extends SearchDelegate {
  List<String> suggestions = [
    "USA",
    "China",
    "Australia",
  ];
  @override
  List<Widget>? buildActions(BuildContext context) => [
        IconButton(
            icon: const Icon(Icons.clear),
            onPressed: () {
              query = "";
            })
      ];

  @override
  Widget? buildLeading(BuildContext context) => IconButton(
      icon: const Icon(Icons.arrow_back),
      onPressed: () => close(context, null));

  @override
  Widget buildResults(BuildContext context) {
    List<String> matchQuery = [];
    for (var suggestion in suggestions) {
      if (suggestion.toLowerCase().contains(query.toLowerCase())) {
        matchQuery.add(suggestion);
      }
    }
    return ListView.builder(
      itemCount: matchQuery.length,
      itemBuilder: (context, index) {
        var result = matchQuery[index];
        return ListTile(
          title: Text(result),
        );
      },
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return ListView.builder(
      itemCount: suggestions.length,
      itemBuilder: (context, index) {
        final suggestion = suggestions[index];

        return ListTile(
          title: Text(suggestion),
          onTap: () {
            query = suggestion;
          },
        );
      },
    );
  }
}

2

Answers


  1. Separate Your code like this, then your issue will be fixed.I assume this is happening because you are using the Material app context instead of the home context

    class MainApp extends StatelessWidget {
      const MainApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(home: Home());
      }
    }
    
    class Home extends StatelessWidget {
      const Home({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Raincheck"),
            actions: [
              IconButton(
                icon: const Icon(Icons.search),
                onPressed: () {
                  showSearch(
                    context: context,
                    delegate: LocationSearchDelegate(),
                  );
                },
              ),
              //   IconButton(
              //     onPressed: () {},
              //     icon: const Icon(Icons.settings),
              //   )
            ],
          ),
          body: const Center(
            child: HomePage(),
          ),
        );
      }
    }
    

    I don’t know what is on your homepage, if its a layout without using scaffold I m suggesting that emove that and move all the widgets to the homebody

    Login or Signup to reply.
  2. There’s a very simple answer to what is happening in your code, and it is something that is pretty fundamental to how flutter works.

    Let’s take a look at your code:

    class MainApp extends StatelessWidget {
      const MainApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text("Raincheck"),
              actions: [
                IconButton(
                  icon: const Icon(Icons.search),
                  onPressed: () {
                    showSearch(
                      context: context,                          <<<<<<<<
                      delegate: LocationSearchDelegate(),
                    );
                  },
                ),
    ...
    

    The issue here is that you’re passing MainApp’s context to showSearch. Let’s take a quick look at showSearch‘s implementation:

    Future<T?> showSearch<T>({
      required BuildContext context,
      required SearchDelegate<T> delegate,
      String? query = '',
      bool useRootNavigator = false,
    }) {
      delegate.query = query ?? delegate.query;
      delegate._currentBody = _SearchBody.suggestions;
      return Navigator.of(context, rootNavigator: useRootNavigator).push(_SearchPageRoute<T>(
        delegate: delegate,
      ));
    }
    

    So… in that, they’re calling Navigator.of(context,...). Now back to your code – I’m going to show you the tree of widgets created (-Navigator- and -WidgetApp- (among others) are created implicitly by MaterialApp which is why I’m using the -):

    MainApp     <----- context
      MaterialApp
        -WidgetApp-
          -Navigator-
            Scaffold
              Appbar
                IconButton
    

    So, because the context being passed to showSearch is directed to MainApp, searching for Navigator on it will fail. And just to be clear, WidgetApp and Navigator are created implicitly within MaterialApp. But anyways, what do we need to do? Make sure that the context being passed to showSearch is below the navigator.

    There’s two easy ways to do this. The first would be to split the page from the app, which is honestly a better way of building things anyways. This would mean something like this:

    class MainApp extends StatelessWidget {
      const MainApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          HomePage()
        );
      }
    }
    
    
    class HomePage extends StatelessWidget {
      const HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Raincheck"),
            actions: [
              IconButton(
                icon: const Icon(Icons.search),
                onPressed: () {
                  showSearch(
                    context: context,
                    delegate: LocationSearchDelegate(),
                  );
                },
              ),
            ],
          ),
          body: const Center(
            child: HomeBody(),
          ),
        );
      }
    }
    

    The second way would be to use a builder:

    class MainApp extends StatelessWidget {
      const MainApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Builder(
            builder: (BuildContext subContext) {
              return Scaffold(
                appBar: AppBar(
                  title: const Text("Raincheck"),
                  actions: [
                    IconButton(
                      icon: const Icon(Icons.search),
                      onPressed: () {
                        showSearch(
                          context: subContext,
                          delegate: LocationSearchDelegate(),
                        );
                    },
                  ),
                ],
              ),
              body: const Center(
                child: HomePage(),
              ),
            ),
          )},
        )
      );
    }
    

    Either of those solutions make sure that the context or subContext being used by the showSearch function are actually below the Navigator‘s context.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search